SQL:使用所有可能的组合进行更新

标签 sql postgresql routes combinatorics variations

我有关系

+-----+----+
| 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。

末端应该看起来像这样,但是应该向更多的人开放(例如为D1额外添加一个D3)
+-------+-----+----+
| 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 |
+-------+-----+----+


编辑:

另一个可能的替换表可能是
+----+-------+
| id | alter |
+----+-------+
| B1 | B2    |
| D1 | D2    |
| D1 | D3    |
+----+-------+

可能会导致6组(我希望我没有忘记一个案子)
+-------+-----+----+
| 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 | B2 |
|     3 |   3 | C1 |
|     3 |   4 | D2 |
|     4 |   1 | A1 |
|     4 |   2 | B2 |
|     4 |   3 | C1 |
|     4 |   4 | D3 |
|     5 |   1 | A1 |
|     5 |   2 | B1 |
|     5 |   3 | C1 |
|     5 |   4 | D2 |
|     6 |   1 | A1 |
|     6 |   2 | B1 |
|     6 |   3 | C1 |
|     6 |   4 | D3 |
+-------+-----+----+


如果您有三个替代品,例如
+----+-------+
| id | alter |
+----+-------+
| B1 | B2    |
| C1 | C2    |
| D1 | D3    |
+----+-------+

这将导致8组。
到目前为止,我所做的尝试并没有真正的帮助:

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;

我很高兴为标题提供更好的建议。

最佳答案

修改问题后的答案已更新

这个问题中最棘手的部分是生成替换的功率集。但是,幸运的是,postgres支持递归查询,并且可以递归计算幂集。因此,我们可以为该问题建立一个通用的解决方案,无论替换集的大小如何,该解决方案都将起作用。

让我们将第一个表称为source,将第二个表称为replacements,我将避免使用其他名称来代替讨厌的名称alter:

CREATE TABLE source (seq, id) as (
  VALUES (1, 'A1'), (2, 'B1'), (3, 'C1'), (4, 'D1')
);
CREATE TABLE replacements (id, sub) as (
  VALUES ('B1', 'B2'), ('D1', 'D2')
);

需要生成要替换的ID的第一个功率集。空集可能会被省略,因为它无论如何都无法与联接一起使用,最后source表可以被union'到中间结果以提供相同的输出。

在递归步骤中,JOIN条件rec.id > repl.id确保每个id对于每个生成的子集仅出现一次。

最后一步:

交叉联接将源散开N次,其中N是替换的非空组合数(有变化)

组名是使用seq上经过过滤的运行时总和生成的。

如果替换ID等于源ID,则子集是未嵌套的&合并ID。
WITH RECURSIVE rec AS (
  SELECT ARRAY[(id, sub)] subset, id FROM replacements
  UNION ALL
  SELECT subset || (repl.id, sub), repl.id 
  FROM replacements repl 
  JOIN rec ON rec.id > repl.id
)
SELECT NULL subset, 0 set_name, seq, id FROM source
UNION ALL
SELECT subset
, SUM(seq) FILTER (WHERE seq = 1) OVER (ORDER BY subset, seq) set_name 
, seq
, COALESCE(sub, source.id) id
FROM rec 
CROSS JOIN source
LEFT JOIN LATERAL (
  SELECT id, sub 
  FROM unnest(subset) x(id TEXT, sub TEXT)
  ) x ON source.id = x.id;

测验

使用替换值('B1', 'B2'), ('D1', 'D2'),查询返回4个组。
        subset         | set_name | seq | id 
-----------------------+----------+-----+----
                       |        0 |   1 | A1
                       |        0 |   2 | B1
                       |        0 |   3 | C1
                       |        0 |   4 | D1
 {"(B1,B2)"}           |        1 |   1 | A1
 {"(B1,B2)"}           |        1 |   2 | B2
 {"(B1,B2)"}           |        1 |   3 | C1
 {"(B1,B2)"}           |        1 |   4 | D1
 {"(D1,D2)"}           |        2 |   1 | A1
 {"(D1,D2)"}           |        2 |   2 | B1
 {"(D1,D2)"}           |        2 |   3 | C1
 {"(D1,D2)"}           |        2 |   4 | D2
 {"(D1,D2)","(B1,B2)"} |        3 |   1 | A1
 {"(D1,D2)","(B1,B2)"} |        3 |   2 | B2
 {"(D1,D2)","(B1,B2)"} |        3 |   3 | C1
 {"(D1,D2)","(B1,B2)"} |        3 |   4 | D2
(16 rows)

使用替换值('B1', 'B2'), ('D1', 'D2'), ('D1', 'D3'),该查询返回6组:
        subset         | set_name | seq | id 
-----------------------+----------+-----+----
                       |        0 |   1 | A1
                       |        0 |   2 | B1
                       |        0 |   3 | C1
                       |        0 |   4 | D1
 {"(B1,B2)"}           |        1 |   1 | A1
 {"(B1,B2)"}           |        1 |   2 | B2
 {"(B1,B2)"}           |        1 |   3 | C1
 {"(B1,B2)"}           |        1 |   4 | D1
 {"(D1,D2)"}           |        2 |   1 | A1
 {"(D1,D2)"}           |        2 |   2 | B1
 {"(D1,D2)"}           |        2 |   3 | C1
 {"(D1,D2)"}           |        2 |   4 | D2
 {"(D1,D2)","(B1,B2)"} |        3 |   1 | A1
 {"(D1,D2)","(B1,B2)"} |        3 |   2 | B2
 {"(D1,D2)","(B1,B2)"} |        3 |   3 | C1
 {"(D1,D2)","(B1,B2)"} |        3 |   4 | D2
 {"(D1,D3)"}           |        4 |   1 | A1
 {"(D1,D3)"}           |        4 |   2 | B1
 {"(D1,D3)"}           |        4 |   3 | C1
 {"(D1,D3)"}           |        4 |   4 | D3
 {"(D1,D3)","(B1,B2)"} |        5 |   1 | A1
 {"(D1,D3)","(B1,B2)"} |        5 |   2 | B2
 {"(D1,D3)","(B1,B2)"} |        5 |   3 | C1
 {"(D1,D3)","(B1,B2)"} |        5 |   4 | D3
(24 rows)

使用替换值('B1', 'B2'), ('C1', 'C2'), ('D1', 'D2'),查询返回8组:
             subset              | set_name | seq | id 
---------------------------------+----------+-----+----
                                 |        0 |   1 | A1
                                 |        0 |   2 | B1
                                 |        0 |   3 | C1
                                 |        0 |   4 | D1
 {"(B1,B2)"}                     |        1 |   1 | A1
 {"(B1,B2)"}                     |        1 |   2 | B2
 {"(B1,B2)"}                     |        1 |   3 | C1
 {"(B1,B2)"}                     |        1 |   4 | D1
 {"(C1,C2)"}                     |        2 |   1 | A1
 {"(C1,C2)"}                     |        2 |   2 | B1
 {"(C1,C2)"}                     |        2 |   3 | C2
 {"(C1,C2)"}                     |        2 |   4 | D1
 {"(C1,C2)","(B1,B2)"}           |        3 |   1 | A1
 {"(C1,C2)","(B1,B2)"}           |        3 |   2 | B2
 {"(C1,C2)","(B1,B2)"}           |        3 |   3 | C2
 {"(C1,C2)","(B1,B2)"}           |        3 |   4 | D1
 {"(D1,D2)"}                     |        4 |   1 | A1
 {"(D1,D2)"}                     |        4 |   2 | B1
 {"(D1,D2)"}                     |        4 |   3 | C1
 {"(D1,D2)"}                     |        4 |   4 | D2
 {"(D1,D2)","(B1,B2)"}           |        5 |   1 | A1
 {"(D1,D2)","(B1,B2)"}           |        5 |   2 | B2
 {"(D1,D2)","(B1,B2)"}           |        5 |   3 | C1
 {"(D1,D2)","(B1,B2)"}           |        5 |   4 | D2
 {"(D1,D2)","(C1,C2)"}           |        6 |   1 | A1
 {"(D1,D2)","(C1,C2)"}           |        6 |   2 | B1
 {"(D1,D2)","(C1,C2)"}           |        6 |   3 | C2
 {"(D1,D2)","(C1,C2)"}           |        6 |   4 | D2
 {"(D1,D2)","(C1,C2)","(B1,B2)"} |        7 |   1 | A1
 {"(D1,D2)","(C1,C2)","(B1,B2)"} |        7 |   2 | B2
 {"(D1,D2)","(C1,C2)","(B1,B2)"} |        7 |   3 | C2
 {"(D1,D2)","(C1,C2)","(B1,B2)"} |        7 |   4 | D2
(32 rows)

关于SQL:使用所有可能的组合进行更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61106218/

相关文章:

sql - Access SQL 查询 - 选择许多不同类型字符串的中间部分

mysql - 使用 sql DISTINCT 获取唯一行列表

sql - 使用 JPA/Hibernate 进行国际化的最优雅的解决方案?

python - Postgres : is set_config(). current_setting() 应用程序变量的私有(private)/稳健堆栈?

php - Laravel 将参数值从路由固定到 Controller

javascript - 立即访问 Angular 4 查询参数?

mysql - 数据库如何在 B-Tree/B+Tree 内部存储数据

arrays - 如何在 PostgreSQL 12 中将元素添加到 jsonb 数组中?

php - PHP PDO(使用 libpq V 9.1.4)绑定(bind)以使用 CITEXT 的解决方法?

ruby-on-rails - Rails Route Helper中的插值