SQL: обновление со всеми возможными комбинациями - PullRequest
1 голос
/ 08 апреля 2020

У меня есть отношение

+-----+----+
| seq | id |
+-----+----+
|   1 | A1 |
|   2 | B1 |
|   3 | C1 |
|   4 | D1 |
+-----+----+

и я хочу присоединить его к PostgreSQL с

+----+-------+
| id | alter |
+----+-------+
| B1 | B2    |
| D1 | D2    |
+----+-------+

, чтобы я получил все возможные комбинации замены (т.е. декартово произведение замены более менее). Таким образом, группа 1 не имеет обновлений, группа 2 только B2, группа 3 только D2 и группа 4 и B2, и D2.

Конец должен выглядеть следующим образом, но должен быть открыт для большего (например, дополнительный D3 для D1)

+-------+-----+----+
| group | seq | id |
+-------+-----+----+
|     1 |   1 | A1 |
|     1 |   2 | B1 |
|     1 |   3 | C1 |
|     1 |   4 | D1 |
|     2 |   1 | A1 |
|     2 |   2 | B2 |
|     2 |   3 | C1 |
|     2 |   4 | D1 |
|     3 |   1 | A1 |
|     3 |   2 | B1 |
|     3 |   3 | C1 |
|     3 |   4 | D2 |
|     4 |   1 | A1 |
|     4 |   2 | B2 |
|     4 |   3 | C1 |
|     4 |   4 | D2 |
+-------+-----+----+

То, что я пробовал до сих пор, не очень помогло:


WITH a as (SELECT * FROM (values (1,'A1'),(2,'B1'), (3,'C1'), (4,'D1')   ) as a1(seq, id) )
, b as (SELECT * FROM (values ('B1','B2'), ('D1','D2')) as b1(id,alter) )
---------
SELECT row_number() OVER (PARTITION BY a.id) as g, * FROM 
a
CROSS JOIN  b as b1
CROSS JOIN  b as b2
LEFT JOIN b as b3 ON a.id=b3.id
ORDER by g,seq;

и я рад за лучшие предложения с названием.

Ответы [ 2 ]

1 голос
/ 08 апреля 2020

Я могу думать только о приближении грубой силы. Перечислите группы и умножьте вторую таблицу - так, по одному набору строк для каждой группы.

Далее следует использование битовых манипуляций для выбора значения:

WITH a as (
      SELECT * FROM (values (1,'A1'),(2,'B1'), (3,'C1'), (4,'D1')   ) as a1(seq, id)
      ),
     b as (
      SELECT * FROM (values ('B1','B2'), ('D1','D2')) as b1(id,alter)
     ),
     bgroups as (
      SELECT b.*, grp - 1 as grp, ROW_NUMBER() OVER (PARTITION BY grp ORDER BY id) - 1 as seqnum
      FROM b CROSS JOIN
           GENERATE_SERIES(1, (SELECT POWER(2, COUNT(*))::int FROM b)) gs(grp)
     )
SELECT bg.grp, a.seq, 
       COALESCE(MAX(CASE WHEN a.id = bg.id AND (POWER(2, bg.seqnum)::int & bg.grp) > 0 THEN bg.alter END),
                MAX(a.id)
               ) as id
FROM a CROSS JOIN
     bgroups bg
GROUP BY bg.grp, a.seq
ORDER BY bg.grp, a.seq;

Здесь - это дб <> скрипка.

0 голосов
/ 03 мая 2020

Таким образом, группа 1 не имеет обновлений, группа 2 только B2, группа 3 только D2 и группа 4 и B2, и D2.

Поскольку лог c этого оператора не в таблице я решил добавить эту логику c в таблицу c, которая добавляет 3 новых столбца к существующей таблице a, в зависимости от того, какой выбор поля необходимо было рассмотреть.

WITH a as (SELECT * FROM (values (1,'A1'),(2,'B1'), (3,'C1'), (4,'D1')   ) as a1(seq, id) )
, b as (SELECT * FROM (values ('B1','B2'), ('D1','D2')) as b1(id,alter) )
, c as (
SELECT a.seq, a.id,
COALESCE(b1.alter,a.id) as id2,
COALESCE(b2.alter,a.id) as id3,
COALESCE(b3.alter,a.id) as id4
FROM a
LEFT JOIN (SELECT * FROM b WHERE b.alter='B2') b1 ON a.id = b1.id
LEFT JOIN (SELECT * FROM b WHERE b.alter='D2') b2 ON a.id = b2.id
LEFT JOIN (SELECT * FROM b WHERE b.alter IN ('B2','D2')) b3 ON a.id = b3.id)
, d as (SELECT * FROM (values (1),(2), (3), (4)   ) as d1(gr) )



SELECT d.gr,
CASE d.gr
   WHEN 1 THEN c.id
   WHEN 2 THEN c.id2
   WHEN 3 THEN c.id3
   WHEN 4 THEN c.id4 END as id

FROM d
CROSS JOIN  c
ORDER by d.gr, c.seq
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...