Postgresql: вставить декартово произведение двух или более наборов - PullRequest
4 голосов
/ 13 июля 2011

как определение: декартово произведение двух множеств - это множество всех возможных пар этих множеств, поэтому {A, B} x {a, b} = {(A, a), (A, b), (B, a), (B, b)}.

Теперь я хочу вставить такое декартово произведение в таблицу базы данных (каждая пара в виде строки).Он предназначен для заполнения таблицы значениями по умолчанию для каждой пары, поэтому в данный момент в базе данных нет данных, то есть двух наборов.

Есть идеи, как этого добиться с помощью postgresql?

РЕДАКТИРОВАТЬ:

С помощью ответа Гжегожа Шпетковского я смог создать запрос, который выполняет то, что я хочу достичь, но на самом деле это не самый красивый.Предположим, я хочу вставить декартово произведение множеств {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

Есть ли лучший способ сделать это?

РЕДАКТИРОВАТЬ2: Принятый ответ в порядке, но я нашел другую версию, которая может быть подходящей, если она становится более сложной:

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 Ответ

8 голосов
/ 13 июля 2011

Я не уверен, что это действительно отвечает на ваш вопрос, но в PostgreSQL есть CROSS JOIN, определяемый как:

Для каждой возможной комбинации строк из T1 и T2 (т.е. декартово произведение ), объединенная таблица будет содержать строку, состоящую из все столбцы в T1, за которыми следуют все столбцы в T2. Если таблицы имеют N и M строк соответственно, объединенная таблица будет иметь N * M строк.

ИЗ T1 CROSS JOIN T2 эквивалентно FROM T1, T2. Это также эквивалент ВНУТРЕННЕГО СОЕДИНЕНИЯ ОТ T1 НА T2 (см. ниже).

EDIT:

Один из способов - использовать Списки ЗНАЧЕНИЙ (обратите внимание, что на самом деле у вас нет заказа, используйте выражение 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...