Объединение, которое «выделяет» из доступных строк - PullRequest
0 голосов
/ 05 декабря 2018

У меня есть таблица X, которую я хочу обновить в соответствии с записями в другой таблице Y. Соединение между ними не является уникальным.Однако я хочу, чтобы каждая запись в Y обновляла другую запись в X.

Так что если у меня есть таблица X:

i (unique)  k           v         
----------  ----------  ----------
p           100         b         
q           101         a         
r           202         x         
s           301         a         

и таблица Y:

k (unique)  v         
----------  ----------
0           a         
1           b         
2           a         
3           c         
4           a         

Я хочу закончить с таблицей X как:

i           k           v
----------  ----------  ----------
p           1           b
q           0           a
r           202         x
s           2           a

Важным результатом здесь является то, что две строки в X с v = 'a' были обновлены до двух разных значенийof k от Y. (Неважно, какие из них.)

В настоящее время этот результат достигается с помощью дополнительного столбца и программы, примерно такой:

UPDATE X SET X.used = FALSE;
for Yk, Yv in Y:
    UPDATE X
       SET X.k = Yk,
           X.used = TRUE
     WHERE X.i IN (SELECT X.i FROM X
                    WHERE X.v = Yv AND NOT X.used
                    LIMIT 1);

Другими словами,четкость достигается путем «использования» строк в Y. Это не очень хорошо масштабируется.

(я использую SQLite3 и Python, но не позволяйте этому ограничивать вас.)

1 Ответ

0 голосов
/ 06 декабря 2018

Эту проблему можно решить, используя rowids для объединения результатов объединения.Оконные функции не нужны.(Спасибо xQbert за указание меня в этом направлении.)

Сначала мы сортируем две таблицы по v, чтобы сделать таблицы со строками строк в подходящем порядке для объединения.

CREATE TEMPORARY TABLE Xv AS SELECT * FROM X ORDER BY v;
CREATE TEMPORARY TABLE Yv AS SELECT * FROM Y ORDER BY v;

Затем мы можем выбрать минимальный идентификатор строки для каждого значения v, чтобы создать «zip-соединение» для этого значения, объединяя строки в ряд.

SELECT i, Yv.k, Xv.v
  FROM Xv JOIN Yv USING (v)
       JOIN (SELECT v, min(Xv.rowid) AS r FROM Xv GROUP BY v) AS xmin USING (v)
       JOIN (SELECT v, min(Yv.rowid) AS r FROM Yv GROUP BY v) AS ymin
         ON ymin.v = Xv.v AND Xv.rowid - xmin.r = Yv.rowid - ymin.r;

предложение Xv.rowid - min.x = Yv.rowid - min.y - хитрость: оно выполняет попарное сопоставление строк с одинаковым значением v, по существу выделяя одно другому.Результат:

i           k           v         
----------  ----------  ----------
q           0           a         
s           2           a         
p           1           b         

В таком случае просто использовать результат этого запроса в ОБНОВЛЕНИИ.

WITH changes AS (<the SELECT above>)
   UPDATE X SET k = (SELECT k FROM changes WHERE i = X.i)
    WHERE i IN (SELECT i FROM changes);

Временные таблицы могут быть ограничены общими значениями v и, возможно, проиндексирован на v, если запрос большой.

Я бы приветствовал уточнения (или ошибки!)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...