Обновите таблицу со значениями от себя, но выбирая по критериям из другой таблицы - PullRequest
0 голосов
/ 20 февраля 2019

У меня есть соединительная таблица, которая состоит только из внешних ключей, например:

 JUNCTION
+-------+-----------+---------+---------+
|  id   | module_id | comp_id | ins_id  |
+-------+-----------+---------+---------+
| 1     | 1         | 2       | 8       |
| 2     | 2         | 4       | 9       |
| 3     | 3         | 4       | 10      |
| 4     | 4         | 1       | 10      |
| 5     | 3         | 5       | 11      |
| 6     | 4         | 1       | 11      |
| 7     | 5         | 42      | 11
+-------+-----------+---------+---------+

Одна из упомянутых таблиц - modules, например, так:

 MODULES
+-----------+---------+---------+
| id        | name    | version |
+-----------+---------+---------+
| 1         | default | 1       |
| 2         | bar     | 1       |
| 3         | foo     | 1       |
| 4         | foo     | 3       |
| 5         | foo     | 2       |
+-----------+---------+---------+

Есть лиспособ в SQL обновить эту таблицу так, чтобы comp_id для идентификатора соединения 4 в таблице соединений обновлялся до comp_id 4 (то же самое имя, что и у модуля 3, но с большей версией), и идентификатор соединения 6получает comp_id 42, который является comp_id предыдущей версии модуля (2), потому что они имеют совпадающие имена и ins_id модуля и т. д. для всех записей, которые имеютэтот же критерий?

В прозе: обновите все ссылки на модули, имеющие comp_id 1 в соединительной таблице, обновив их с помощью comp_id модуля с соответствующим именем модуля, установив его в comp_id модуля с помощьюследующая наименьшая версия, соответствующая ins_id (и может быть ограничена другими столбцами в соединительной таблице)

Или это будет лучше обрабатываться программно, в бизнес-логике?

1 Ответ

0 голосов
/ 21 февраля 2019

Я думаю, что я решил это: ответ - оконные функции (хотя некоторая комбинация объединений могла бы сделать это. Я приближался, но подумал, что это будет более изящно и понятно)

Сначала мне нужно было создать 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;
...