Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Postgresql: Insert the cartesian product of two or more sets

as definition: The cartesian product of two sets is the set of all possible pairs of these sets, so {A,B} x {a,b} = {(A,a),(A,b),(B,a),(B,b)}.

Now i want to insert such a cartesian product into a database table (each pair as a row). It is intended to fill the table with default values for each pair, so the data, i.e. the two sets, are not present in the database at this point.

Any idea how to achieve this with postgresql?

EDIT :

With the help of Grzegorz Szpetkowski's answer I was able to produce a query that does what I want to achieve, but it really isn't the prettiest one. Suppose I want to insert the cartesian product of the sets {1,2,3} and {'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

Is there any better way to do this?

EDIT2 : Accepted answer is fine, but i found another version which might be appropriate if it gets more complex:

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";
like image 687
aRestless Avatar asked Jul 13 '11 18:07

aRestless


People also ask

What is Cartesian product in PostgreSQL?

How does Cross Join work in PostgreSQL? The Cross Join creates a cartesian product between two sets of data. This type of join does not maintain any relationship between the sets; instead returns the result, which is the number of rows in the first table multiplied by the number of rows in the second table.

How do I add multiple values in PostgreSQL?

PostgreSQL INSERT Multiple Rows First, specify the name of the table that you want to insert data after the INSERT INTO keywords. Second, list the required columns or all columns of the table in parentheses that follow the table name. Third, supply a comma-separated list of rows after the VALUES keyword.

What is Ordinality in PostgreSQL?

This column numbers the rows of the function result set, starting from 1. (This is a generalization of the SQL-standard syntax for UNNEST ... WITH ORDINALITY .) By default, the ordinal column is called ordinality , but a different column name can be assigned to it using an AS clause.

How many inserts can Postgres handle per second?

When using Postgres if you do need writes exceeding 10,000s of INSERT s per second we turn to the Postgres COPY utility for bulk loading. COPY is capable of handling 100,000s of writes per second. Even without a sustained high write throughput COPY can be handy to quickly ingest a very large set of data.


1 Answers

I am not sure if this really answers your question, but in PostgreSQL there is CROSS JOIN defined as:

For every possible combination of rows from T1 and T2 (i.e., a Cartesian product), the joined table will contain a row consisting of all columns in T1 followed by all columns in T2. If the tables have N and M rows respectively, the joined table will have N * M rows.

FROM T1 CROSS JOIN T2 is equivalent to FROM T1, T2. It is also equivalent to FROM T1 INNER JOIN T2 ON TRUE (see below).

EDIT:

One way is to use VALUES Lists (note that in fact you have no order, use ORDER BY clause to get some ordering):

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

Result:

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

BTW:

For more numbers I believe it's handle to use generate_series function, e.g.:

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;

Result:

 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)
like image 84
Grzegorz Szpetkowski Avatar answered Sep 28 '22 02:09

Grzegorz Szpetkowski