Postgresql:插入两组或更多组的笛卡尔积

时间:2011-07-13 18:02:18

标签: sql postgresql cartesian-product

作为定义:两个集合的笛卡尔乘积是这些集合的所有可能对的集合,因此{A,B} x {a,b} = {(A,a),(A,b),( b,A),(b,b)}。

现在我想将这样的笛卡尔积插入数据库表(每对作为一行)。它旨在用每个对的默认值填充表,因此此时数据(即两组)不存在于数据库中。

知道如何用postgresql实现这个目的吗?

编辑:

在Grzegorz Szpetkowski的回答的帮助下,我能够产生一个能够实现我想要实现的目标的查询,但它确实不是最漂亮的。假设我要插入集合{1,2,3}和{'A','B','C'}的笛卡尔积。

INSERT INTO "Test"
SELECT * FROM
(SELECT 1 UNION SELECT 2 UNION SELECT 3) P
CROSS JOIN
(SELECT 'A' UNION SELECT 'B' UNION SELECT 'C') Q

有没有更好的方法呢?

EDIT2: 接受的答案很好,但我找到了另一个版本,如果它变得更复杂可能是合适的:

CREATE TEMP TABLE "Numbers" (ID integer) ON COMMIT DROP;
CREATE TEMP TABLE "Chars" (Char character varying) ON COMMIT DROP;
INSERT INTO "Numbers" (ID) VALUES (1),(2),(3);
INSERT INTO "Chars" (Char) VALUES ('A'),('B'),('C');
INSERT INTO "Test"
SELECT * FROM
"Numbers"
CROSS JOIN
"Chars";

1 个答案:

答案 0 :(得分:8)

我不确定这是否真的能解答您的问题,但在PostgreSQL中,CROSS JOIN定义为:

  

对于T1和T2的每一个可能的行组合(即a   笛卡儿积),连接表将包含一行   T1中的所有列后跟T2中的所有列。如果表有N.   分别为M行和M行,连接表将有N * M行。

     

FROM T1 CROSS JOIN T2相当于FROM T1,T2。也是   相当于FROM T1 INNER JOIN T2为TRUE(见下文)。

修改

一种方法是使用VALUES Lists(注意事实上你没有订单,使用ORDER BY子句来获得一些排序):

SELECT N AS number, L AS letter FROM
    (VALUES (1), (2), (3)) a(N)
CROSS JOIN
    (VALUES ('A'), ('B'), ('C')) b(L);

结果:

 number | letter
--------+--------
      1 | A
      1 | B
      1 | C
      2 | A
      2 | B
      2 | C
      3 | A
      3 | B
      3 | C
(9 rows)

<强>顺便说一句

对于更多数字,我认为可以使用generate_series函数,例如:

SELECT n AS number, chr(ascii('A') + L - 1) AS letter
FROM
    generate_series(1, 5) N
CROSS JOIN
    generate_series(1, 5) L
ORDER BY N, L;

结果:

 number | letter
--------+--------
      1 | A
      1 | B
      1 | C
      1 | D
      1 | E
      2 | A
      2 | B
      2 | C
      2 | D
      2 | E
      3 | A
      3 | B
      3 | C
      3 | D
      3 | E
      4 | A
      4 | B
      4 | C
      4 | D
      4 | E
      5 | A
      5 | B
      5 | C
      5 | D
      5 | E
(25 rows)