From cc22119667eaa37f5beb5e1c508ca72bc1e5ae84 Mon Sep 17 00:00:00 2001 From: Fredrik Ringqvist <35255659+fredrikphotowall@users.noreply.github.com> Date: Tue, 17 Oct 2023 11:02:40 +0200 Subject: [PATCH] Reassign product interiors (#355) --- migrations/000.444.sql | 331 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 migrations/000.444.sql diff --git a/migrations/000.444.sql b/migrations/000.444.sql new file mode 100644 index 0000000..0dc2890 --- /dev/null +++ b/migrations/000.444.sql @@ -0,0 +1,331 @@ +-- 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 \ No newline at end of file