Как установить уникальные значения столбца, используя обновление из оператора select - PullRequest
1 голос
/ 24 марта 2020

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

Пусть код говорит в примере:

/* (Re-)create first table */
DROP TABLE IF EXISTS Nodes;
CREATE TABLE Nodes (
    ID   INTEGER PRIMARY KEY AUTOINCREMENT
                 UNIQUE
                 NOT NULL,
    Data INTEGER NOT NULL
);
/* Fill some data into the first table */
INSERT INTO Nodes (Data) VALUES (2), (3), (9), (20), (19), (13), (29), (25), (9), (25), (20), (24);


/* (Re-)create second table */
DROP TABLE IF EXISTS Links;
CREATE TABLE Links (
    ID     INTEGER PRIMARY KEY AUTOINCREMENT
                   UNIQUE
                   NOT NULL,
    Data   INTEGER NOT NULL,
    NodeID INTEGER
);
/* Fill some data into the second table */
INSERT INTO Links (Data) VALUES (9), (9), (13), (19), (20), (20), (21), (24), (25), (25), (29), (30), (32);

/* Now try to macht the two tables */
UPDATE Links
   SET NodeID = (
       SELECT Nodes.ID
         FROM Nodes
        WHERE Nodes.Data = Links.Data
          /* The following line seems to be executed once per Update, but not for each row of the update, which seems to be my problem */
          AND Nodes.ID NOT IN (SELECT NodeID FROM Links WHERE NodeID IS NOT NULL) );

Мой ожидаемый результат будет примерно таким:

Links:
 ID | Data | NodeID
----+------+--------
  1 |    9 |     3
  2 |    9 |     9
...
  5 |   20 |     4
  6 |   20 |    11

Тем не менее, я получаю:

Links:
 ID | Data | NodeID
----+------+--------
  1 |    9 |     3
  2 |    9 |     3  <- Fail
...
  5 |   20 |     4
  6 |   20 |     4  <- Fail

Ну, как уже упоминалось в комментарии над последней строкой кода: Моя проблема в том, что обновление игнорирует ранее обновленные строки и, таким образом, вставляет один Nodes.ID многократно. Однако я хочу, чтобы столбец Links.NodeID был уникальным после этого шага. (Не уникально в целом, но для этого шага)

Есть идеи о том, как этого добиться? Я благодарен за любой совет или идею, поскольку я терплю неудачу в этом в течение многих дней.

Большое спасибо, DonLuigi

1 Ответ

1 голос
/ 24 марта 2020

Используйте ROW_NUMBER() оконную функцию в каждой из таблиц, чтобы вы могли правильно связать строки, которые вы хотите обновить:

UPDATE Links
SET NodeID = (
  SELECT n.ID
  FROM (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY Data ORDER BY ID) rn
    FROM Nodes
  ) n INNER JOIN (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY Data ORDER BY ID) rn
    FROM Links  
  ) l ON l.Data = n.Data AND l.rn = n.rn  
  WHERE n.Data = Links.Data AND l.ID = Links.ID
);

См. Демонстрационную версию . Или с CTE:

WITH cte AS (
  SELECT n.ID nID, n.Data nData, l.ID lID, l.Data lData, l.NodeID lNodeID
  FROM (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY Data ORDER BY ID) rn
    FROM Nodes
  ) n INNER JOIN (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY Data ORDER BY ID) rn
    FROM Links  
  ) l ON l.Data = n.Data AND l.rn = n.rn   
)  
UPDATE Links
SET NodeID = (
  SELECT nID FROM cte
  WHERE nData = Links.Data AND lID = Links.ID
);

См. Демоверсию . Результаты:

| ID  | Data | NodeID |
| --- | ---- | ------ |
| 1   | 9    | 3      |
| 2   | 9    | 9      |
| 3   | 13   | 6      |
| 4   | 19   | 5      |
| 5   | 20   | 4      |
| 6   | 20   | 11     |
| 7   | 21   |        |
| 8   | 24   | 12     |
| 9   | 25   | 8      |
| 10  | 25   | 10     |
| 11  | 29   | 7      |
| 12  | 30   |        |
| 13  | 32   |        |
...