-- Reassign product interior assignments based on rules by Malin from -- https://nordicetrade-my.sharepoint.com/:x:/g/personal/malin_photowall_se/EaGIC8JX5KlBsI90kreSMX0B4wBRAsjL1ghDN8DQ0waQNw?e=GV93tN -- -- Using the rules below, we will convert the percentages into ranges that we can match against: -- (50%, 50%) => (1-50, 51-100), (100% => 1-100), (20%, 40%, 40%) => (1-20, 21-60, 61-100), etc -- -- We then assign a random number between 1 and 100 to every product interior we have that uses the old rooms. -- -- The random number determines which new room to use, and we update accordingly. -- It will not create a 100% perfect distribution, but acceptable for our purpose. -- If you modify this script according to comments at the end, you will see a debug output of the results. -- -- One situation had not been anticipated: sometimes we try to create a print product-room combo that already existed. -- Either because it was already assigned before running the script, or because two rules assigned the same new room -- to a print product. Because of the late realization, this is handled at the end (by ignoring one of them), -- skewing the percentages a bit. -- -- -- The rules: -- -- Interiors that should be replaced completely (assign 100% to new room/s): -- old interior => new rooms (100% if not specified) -- room01_wallpaper_landscape => 103 -- room02_wallpaper_landscape => 84 (50%), 88 (50%) -- room03_wallpaper_landscape => 75 -- room04_wallpaper_landscape => 91 -- room05_wallpaper_landscape => 84 -- room06_wallpaper_landscape => 71 -- room07_wallpaper_landscape => 76 -- room08_wallpaper_landscape => 103 -- room09_wallpaper_landscape => 84 -- room10_wallpaper_landscape => 85 -- room11_wallpaper_landscape => 88 -- room12_wallpaper_landscape => 84 -- room36_wallpaper_landscape => 82 -- room37_wallpaper_landscape => 85 -- room54_wallpaper_landscape => 105 -- room58_wallpaper_landscape => 93 -- room59_wallpaper_landscape => 105 -- -- Interiors that should be partially replaced -- room38_wallpaper_landscape => 87 (30%), 111 (30%), 100 (20%), self (20%) -- room41_wallpaper_landscape => 88 (50%), 99 (20%), self (30%) -- room43_wallpaper_landscape => 92 (20%), 90 (20%), 91 (10%), self (50%) -- room44_wallpaper_landscape => 103 (50%), self (50%) -- room46_wallpaper_landscape => 87 (30%), 85 (30%), self (40%) -- room47_wallpaper_landscape => 89 (40%), 102 (20%), self (40%) -- room48_wallpaper_landscape => 89 (40%), 86 (20%), 106 (10%), self (30%) -- room49_wallpaper_landscape => 112 (10%), 107 (10%), 108 (10%), self (70%) -- room50_wallpaper_landscape => 70 (20%), 75 (20%), 76 (20%), 74 (10%), self (30%) -- room51_wallpaper_landscape => 77 (20%), 78 (20%), 79 (20%), self (40%) -- room52_wallpaper_landscape => 76 (50%), self (50%) -- room53_wallpaper_landscape => 72 (30%), 71 (30%), self (40%) -- room55_wallpaper_landscape => 80 (50%), self (50%) -- room57_wallpaper_landscape => 98 (50%), self (50%) -- room61_wallpaper_landscape => 83 (30%), 105 (30%), 104 (10%), self (30%) -- room62_wallpaper_landscape => 94 (30%), 96 (30%), 101 (20%), self (20%) -- room63_wallpaper_landscape => 97 (50%), self (50%) -- room64_wallpaper_landscape => 95 (50%), self (50%) -- room69_wallpaper_landscape => 73 (30%), 81 (30%), self (40%) -- -- -- -- STEP 1: Store the rules in a table (using a real table instead of a temporary table to allow foreign keys) drop table if exists temp_interiors_to_change; create table temp_interiors_to_change ( old_room_number int references rooms (id) not null, new_room_number int references rooms (id) not null, percentage int not null check(percentage >= 1 and percentage <=100), unique(old_room_number, new_room_number) ); insert into temp_interiors_to_change(old_room_number, new_room_number, percentage) values (1, 103, 100), (2, 84, 50), (2, 88, 50), (3, 75, 100), (4, 91, 100), (5, 84, 100), (6, 71, 100), (7, 76, 100), (8, 103, 100), (9, 84, 100), (10, 85, 100), (11, 88, 100), (12, 84, 100), (36, 82, 100), (37, 85, 100), (54, 105, 100), (58, 93, 100), (59, 105, 100), (38, 87, 30), (38, 111, 30), (38, 100, 20), (38, 38, 20), (41, 88, 50), (41, 99, 20), (41, 41, 30), (43, 92, 20), (43, 90, 20), (43, 91, 10), (43, 43, 50), (44, 103, 50), (44, 44, 50), (46, 87, 30), (46, 85, 30), (46, 46, 40), (47, 89, 40), (47, 102, 20), (47, 47, 40), (48, 89, 40), (48, 86, 20), (48, 106, 10), (48, 48, 30), (49, 112, 10), (49, 107, 10), (49, 108, 10), (49, 49, 70), (50, 70, 20), (50, 75, 20), (50, 76, 20), (50, 74, 10), (50, 50, 30), (51, 77, 20), (51, 78, 20), (51, 79, 20), (51, 51, 40), (52, 76, 50), (52, 52, 50), (53, 72, 30), (53, 71, 30), (53, 53, 40), (55, 80, 50), (55, 55, 50), (57, 98, 50), (57, 57, 50), (61, 83, 30), (61, 105, 30), (61, 104, 10), (61, 61, 30), (62, 94, 30), (62, 96, 30), (62, 101, 20), (62, 62, 20), (63, 97, 50), (63, 63, 50), (64, 95, 50), (64, 64, 50), (69, 73, 30), (69, 81, 30), (69, 69, 40) ; -- STEP 2. Add an internal number 1-4 for each new room assigned to an old room -- with_internal_ids: -- old_room_number | new_room_number | percentage | internal_id -- -----------------+-----------------+------------+------------- -- 1 | 103 | 100 | 1 -- 2 | 84 | 50 | 1 -- 2 | 88 | 50 | 2 -- 37 | 85 | 100 | 1 -- 38 | 38 | 20 | 1 -- 38 | 87 | 30 | 2 -- 38 | 100 | 20 | 3 -- 38 | 111 | 30 | 4 with with_internal_ids as ( select *, (row_number() over (partition by old_room_number)) as internal_id from temp_interiors_to_change order by 1 ), -- STEP 3. Calculate the start and end numbers for each room, based on its percentage on how much it should be used -- with_start_and_end_numbers: -- old_room_number | new_room_number | percentage | internal_id | start_number | up_to -- -----------------+-----------------+------------+-------------+--------------+------- -- 1 | 103 | 100 | 1 | 1 | 100 -- 2 | 84 | 50 | 1 | 1 | 50 -- 2 | 88 | 50 | 2 | 51 | 100 -- 37 | 85 | 100 | 1 | 1 | 100 -- 38 | 38 | 20 | 1 | 1 | 20 -- 38 | 87 | 30 | 2 | 21 | 50 -- 38 | 100 | 20 | 3 | 51 | 70 -- 38 | 111 | 30 | 4 | 71 | 100 -- 41 | 41 | 30 | 1 | 1 | 30 with_start_number as ( select *, (select coalesce(sum(percentage), 0) + 1 start_number from with_internal_ids wii where wii.old_room_number = main.old_room_number and wii.new_room_number <> main.new_room_number and wii.internal_id < main.internal_id) from with_internal_ids main ), with_start_and_end_numbers as ( select *, (100 - (100 - percentage) + start_number - 1) as up_to from with_start_number ), -- STEP 4. Add the database ids for the rooms. (i.e. room01_wallpaper_landscape is actually id 4 in rooms table) -- room_ids: -- old_room_no | old_room_id | new_no | new_room_id | percentage | start_number | up_to -- -------------+-------------+--------+-------------+------------+--------------+------- -- 1 | 4 | 103 | 332 | 100 | 1 | 100 -- 2 | 8 | 84 | 313 | 50 | 1 | 50 -- 2 | 8 | 88 | 317 | 50 | 51 | 100 -- 38 | 243 | 38 | 243 | 20 | 1 | 20 -- 38 | 243 | 87 | 316 | 30 | 21 | 50 -- 38 | 243 | 100 | 329 | 20 | 51 | 70 -- 38 | 243 | 111 | 340 | 30 | 71 | 100 room_ids as ( select t.old_room_number old_room_no, (select id from rooms where name = 'room' || (CASE WHEN old_room_number < 10 THEN '0' ELSE '' END) || old_room_number ||'_wallpaper_landscape' limit 1) as old_room_id, t.new_room_number new_no, (select id from rooms where name = 'room' || (CASE WHEN new_room_number < 10 THEN '0' ELSE '' END) || new_room_number ||'_wallpaper_landscape' limit 1) as new_room_id, t.percentage, start_number, up_to from with_start_and_end_numbers t ), -- STEP 5. Select all current product interiors that use the old rooms, and assign each a random number 1-100. -- affected_interiors: -- id | room_id | random1to100 -- --------+---------+-------------- -- 528448 | 255 | 31 -- 536310 | 264 | 1 -- 505329 | 264 | 39 -- 505327 | 280 | 8 -- 522889 | 255 | 86 -- 539476 | 252 | 98 -- 580142 | 261 | 4 -- 562716 | 252 | 58 -- 580143 | 248 | 71 affected_interiors as ( select id, room_id, (floor((random() * 100)) + 1) random1to100 from interiors where interiors.room_id in (select distinct old_room_id from room_ids) ), -- STEP 6. Add which new room the old interior should get, by matching the random number against the start_number and up_to -- interiors_to_potentially_be_updated: -- interior_id | current_room_id | new_room_id -- -------------+-----------------+------------- -- 528448 | 255 | 255 -- 536310 | 264 | 264 -- 505329 | 264 | 264 -- 505327 | 280 | 300 -- 522889 | 255 | 255 -- 539476 | 252 | 319 interiors_to_potentially_update as ( select affected_interiors.id interior_id, affected_interiors.room_id current_room_id, (select new_room_id from room_ids where affected_interiors.room_id = room_ids.old_room_id and random1to100 >= start_number and random1to100 <= up_to limit 1) from affected_interiors ), with_print_ids as ( select interiors_to_potentially_update.*, interiors.print_id from interiors_to_potentially_update join interiors on interiors.id = interiors_to_potentially_update.interior_id ), -- Workaround to handle case where two rules assign the same new room to a print product (will cause error). -- It has to be filtered out before the UPDATE statement, so we give each row a number, and then only select one of them. -- interior_id | current_room_id | new_room_id | print_id | duplicate_order_number -- -------------+-----------------+-------------+----------+------------------------ -- 767310 | 290 | 290 | 189915 | 1 -- 767311 | 283 | 334 | 189915 | 1 -- 767315 | 288 | 334 | 189915 | 2 ranked_to_update as ( select *, row_number() over (partition by print_id, new_room_id order by interior_id) as duplicate_order_number from with_print_ids ), final_update as ( select interior_id, current_room_id, new_room_id from ranked_to_update where duplicate_order_number = 1 ) -- -- FINAL STEP: Update interiors: UPDATE interiors SET room_id = to_update.new_room_id FROM final_update to_update WHERE interiors.id = to_update.interior_id AND to_update.current_room_id <> to_update.new_room_id AND NOT EXISTS ( -- This prevents errors if the printproduct was already assigned to the new room, prior to running the script SELECT 1 FROM interiors existing WHERE existing.print_id = interiors.print_id AND existing.room_id = to_update.new_room_id AND existing.id <> interiors.id ); -- Remove any interiors that were to be 100% replaced, but that we had to ignore due to duplicates delete from interiors where room_id in ( select id from rooms where name in ('room01_wallpaper_landscape', 'room02_wallpaper_landscape', 'room03_wallpaper_landscape', 'room04_wallpaper_landscape', 'room05_wallpaper_landscape', 'room06_wallpaper_landscape', 'room07_wallpaper_landscape', 'room08_wallpaper_landscape', 'room09_wallpaper_landscape', 'room10_wallpaper_landscape', 'room11_wallpaper_landscape', 'room12_wallpaper_landscape', 'room36_wallpaper_landscape', 'room37_wallpaper_landscape', 'room54_wallpaper_landscape', 'room58_wallpaper_landscape', 'room59_wallpaper_landscape') ); DROP TABLE temp_interiors_to_change; -- VERIFICATION/CODE REVIEW: Delete lines 289-305, and uncomment remaining sql below to see example results -- , debug_count_assinged_rooms as ( -- select current_room_id, new_room_id, count(*) as assigned_count -- -- from interiors_to_potentially_update group by 1,2 -- from final_update group by 1,2 -- ), debug_count_total as ( -- select d.*, -- -- (select count(*) from interiors_to_potentially_update i where i.current_room_id = d.current_room_id) as total_count -- (select count(*) from final_update i where i.current_room_id = d.current_room_id) as total_count -- from debug_count_assinged_rooms d -- ), debug_compare as ( -- select -- r.old_room_no old_room_number, -- r.new_no new_room_number, -- r.percentage specified_percentage_for_new_room, -- assigned_count assigned_count_new_room, -- total_count total_count_old_room, -- round((assigned_count*100.0 / total_count), 2) as assigned_percentage, -- round((assigned_count*100.0 / total_count), 2) - percentage as diff_vs_specification -- from -- room_ids r -- left join debug_count_total d on r.old_room_id = d.current_room_id and r.new_room_id = d.new_room_id -- ) select * from debug_compare order by 1,2; -- -- debug_compare: -- -- old_room_number | new_room_number | specified_percentage_for_new_room | assigned_count_new_room | total_count_old_room | assigned_percentage | diff_vs_specification -- -- -----------------+-----------------+-----------------------------------+-------------------------+----------------------+---------------------+----------------------- -- -- 1 | 103 | 100 | 10 | 10 | 100.00 | 0.00 -- -- 2 | 84 | 50 | 753 | 1456 | 51.72 | 1.72 -- -- 2 | 88 | 50 | 703 | 1456 | 48.28 | -1.72 -- -- 3 | 75 | 100 | 3 | 3 | 100.00 | 0.00 -- -- 4 | 91 | 100 | 4 | 4 | 100.00 | 0.00