Я думаю, что я решил это: ответ - оконные функции (хотя некоторая комбинация объединений могла бы сделать это. Я приближался, но подумал, что это будет более изящно и понятно)
Сначала мне нужно было создать CTE, который бы отображал имя и версию модуля на значения в таблице соединений:
WITH module_mapping AS (SELECT j.module_id, j.ins_id, j.comp_id, m.name, m.version
FROM junction AS j
JOIN modules AS m ON m.id = j.module_id
)
с этим CTE, затем я мог бы создать оконную функциюкоторый выбрал бы записи с тем же модулем:
, win AS (SELECT name, version, module_id, ins_id, comp_id, first_value(comp_id)
OVER (PARTITION BY name, ins_id ORDER BY version DESC
ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING)
FROM module_mapping)
Итак, когда я делаю следующий запрос, я вижу, что столбец first_value
содержит записи, которые я ищу:
WITH module_mapping AS (SELECT j.module_id, j.ins_id, j.comp_id, m.name, m.version
FROM junction AS j
JOIN modules AS m ON m.id = j.module_id
)
, win AS (SELECT name, version, module_id, ins_id, comp_id, first_value(comp_id)
OVER (PARTITION BY name, ins_id ORDER BY version DESC
ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING) -- this key part excludes the current row, since it will have the largest (newest) module version
FROM module_mapping)
SELECT * FROM win WHERE comp_id = 1;
+-------+---------+-----------+--------+---------+-------------+
| name | version | module_id | ins_id | comp_id | first_value |
+-------+---------+-----------+--------+---------+-------------+
| "foo" | 3 | 4 | 10 | 1 | 4 |
| "foo" | 3 | 4 | 11 | 1 | 42 |
+-------+---------+-----------+--------+---------+-------------+
Итак, с этими двумя CTE я могу назвать свое обновление sql:
UPDATE junction AS j
SET comp_id = win.new_comp
FROM win
WHERE j.comp_id = 1 -- only change the default ones
AND j.module_id = win.module_id
AND j.ins_id = win.ins_id;