MySQL условное обновление строки на основе других таблиц - PullRequest
0 голосов
/ 18 апреля 2020

У меня есть следующие MySQL таблицы:

CREATE TABLE notification
    (`id` int, `person_id` int, `rule_id` int, `account_id` int, `account_display_name` varchar(16))
;

INSERT INTO notification
    (`id`, `person_id`, `rule_id`, `account_id`, `account_display_name`)
VALUES
    (1, 1, 1, 1, 'Muad''Dib'),
    (2, 1, 1, 2, 'Kwisatz Haderach'),
    (3, 1, 2, 2, 'Kwisatz Haderach'),
    (4, 2, 1, 3, 'Duncan'),
    (5, 2, 2, 4, 'Duncan Idaho')
;


CREATE TABLE person
    (`id` int, `name` varchar(6), `organization_id` int)
;

INSERT INTO person
    (`id`, `name`, `organization_id`)
VALUES
    (1, 'paul', 1),
    (2, 'duncan', 1),
    (3, 'paul', 2),
    (4, 'duncan', 2),
    (5, 'paul', 3),
    (6, 'duncan', 3)
;


CREATE TABLE account
    (`id` int, `display_name` varchar(16), `person_id` int)
;

INSERT INTO account
    (`id`, `display_name`, `person_id`)
VALUES
    (1, 'Muad''Dib', 1),
    (2, 'Kwisatz Haderach', 1),
    (3, 'Duncan', 2),
    (4, 'Duncan Idaho', 2),
    (5, 'Muad''Dib', 3),
    (6, 'Kwisatz Haderach', 3),
    (7, 'Duncan', 4),
    (8, 'Duncan Idaho', 4),
    (9, 'Muad''Dib', 5),
    (10, 'Kwisatz Haderach', 5),
    (11, 'Duncan', 6),
    (12, 'Duncan Idaho', 6)
;


CREATE TABLE organization
    (`id` int, `name` varchar(17))
;

INSERT INTO organization
    (`id`, `name`)
VALUES
    (1, 'atreides'),
    (2, 'atreides_dev'),
    (3, 'atreides_research')
;


CREATE TABLE rule
    (`id` int, `name` varchar(14))
;

INSERT INTO rule
    (`id`, `name`)
VALUES
    (1, 'bug'),
    (2, 'false_positive')
;

Концептуально, рассматриваемая система генерирует notification, когда происходит событие, которое считается относящимся к person. Будет ли генерироваться notification, определяется rule (отношение между person и rule определено в другом месте, но это выходит за рамки этого вопроса). Каждый notification, который генерируется для person, конкретно связан с account, принадлежащим этому person, и он также содержит (денормализованный) account_display_name account.

Обратите внимание, что person также относится только к одному organization.

. В настоящее время у меня есть набор notifications (с соответствующими accounts) для нескольких persons в конкретном organization , Но мне нужно переместить эти notifications в другую реплику organizations (с репликами persons и accounts) на основе rule, вызвавшего notification.

Ниже приведен пример тип миграции, который я пытаюсь выполнить.

состояние связанных таблиц

person
+----+--------+-----------------+
| id |  name  | organization_id |
+----+--------+-----------------+
|  1 | paul   |               1 |
|  2 | duncan |               1 |
|  3 | paul   |               2 |
|  4 | duncan |               2 |
|  5 | paul   |               3 |
|  6 | duncan |               3 |
+----+--------+-----------------+

organization
+----+-------------------+
| id |       name        |
+----+-------------------+
|  1 | atreides          |
|  2 | atreides_dev      |
|  3 | atreides_research |
+----+-------------------+

account
+----+------------------+-----------+
| id |   display_name   | person_id |
+----+------------------+-----------+
|  1 | Muad'Dib         |         1 |
|  2 | Kwisatz Haderach |         1 |
|  3 | Duncan           |         2 |
|  4 | Duncan Idaho     |         2 |
|  5 | Muad'Dib         |         3 |
|  6 | Kwisatz Haderach |         3 |
|  7 | Duncan           |         4 |
|  8 | Duncan Idaho     |         4 |
|  9 | Muad'Dib         |         5 |
| 10 | Kwisatz Haderach |         5 |
| 11 | Duncan           |         6 |
| 12 | Duncan Idaho     |         6 |
+----+------------------+-----------+

rule
+----+----------------+
| id |      name      |
+----+----------------+
|  1 | bug            |
|  2 | false_positive |
+----+----------------+

начальное состояние уведомлений

+----+-----------+---------+------------+----------------------+
| id | person_id | rule_id | account_id | account_display_name |
+----+-----------+---------+------------+----------------------+
|  1 |         1 |       1 |          1 | Muad'Dib             |
|  2 |         1 |       1 |          2 | Kwisatz Haderach     |
|  3 |         1 |       2 |          2 | Kwisatz Haderach     |
|  4 |         2 |       1 |          3 | Duncan               |
|  5 |         2 |       2 |          4 | Duncan Idaho         |
+----+-----------+---------+------------+----------------------+

Конечное состояние уведомлений

+----+-----------+---------+------------+----------------------+
| id | person_id | rule_id | account_id | account_display_name |
+----+-----------+---------+------------+----------------------+
|  1 |         3 |       1 |          5 | Muad'Dib             |
|  2 |         3 |       1 |          6 | Kwisatz Haderach     |
|  3 |         5 |       2 |         10 | Kwisatz Haderach     |
|  4 |         4 |       1 |          7 | Duncan               |
|  5 |         6 |       2 |         12 | Duncan Idaho         |
+----+-----------+---------+------------+----------------------+

Как видите, person_id и account_id notifications были обновлены на основе notification's rule_id. В частности:

  • Каждый notification, созданный bug rule (ID 1), был перемещен в соответствующие реплики person и account в atreides_dev organization ( ID 2).
  • Каждый notification, созданный false_positive rule (ID 2), был перемещен в соответствующие реплики person и account в atreides_research organization (ID 3).

Я написал SQL запрос, который (я считаю) выбирает правильные notification.person_id и notification.account_id на основе notification.rule_id, но я не уверен в лучшем способ использовать это в операторе UPDATE, чтобы каждый notification обновлялся правильно.

Вот SELECT:

select p_replica.id, acc_replica.id as account_id
from (select p.name, person_id, rule_id, account_id, account_display_name from notification n
inner join person p
on n.person_id = p.id
where p.organization_id = 1
and n.rule_id in (1)) as notifications
 inner join person p_replica
 on p_replica.name = notifications.name
 and p_replica.organization_id = 2
 inner join account acc_replica
 on acc_replica.person_id = p_replica.id
 and acc_replica.display_name = notifications.account_display_name;

Обратите внимание, что SELECT указывает источник organization ( ID 1), пункт назначения organization (ID 2) и rule, чей notifications необходимо перенести. Напомним, что это основано на сопоставлении rule с пунктом назначения organization. Другими словами, для выбора всех обновленных notifications потребуется одно выполнение этого запроса на отображение rule -> organization.

Как будет выглядеть запрос UPDATE для выполнения этой миграции?

Вот SQL Fiddle , с которым можно поиграть.

...