305 lines
6.5 KiB
SQL
305 lines
6.5 KiB
SQL
--
|
|
-- JOIN
|
|
-- Test JOIN clauses
|
|
--
|
|
|
|
CREATE TABLE J1_TBL (
|
|
i integer,
|
|
j integer,
|
|
t text
|
|
);
|
|
|
|
CREATE TABLE J2_TBL (
|
|
i integer,
|
|
k integer
|
|
);
|
|
|
|
|
|
INSERT INTO J1_TBL VALUES (1, 4, 'one');
|
|
INSERT INTO J1_TBL VALUES (2, 3, 'two');
|
|
INSERT INTO J1_TBL VALUES (3, 2, 'three');
|
|
INSERT INTO J1_TBL VALUES (4, 1, 'four');
|
|
INSERT INTO J1_TBL VALUES (5, 0, 'five');
|
|
INSERT INTO J1_TBL VALUES (6, 6, 'six');
|
|
INSERT INTO J1_TBL VALUES (7, 7, 'seven');
|
|
INSERT INTO J1_TBL VALUES (8, 8, 'eight');
|
|
INSERT INTO J1_TBL VALUES (0, NULL, 'zero');
|
|
INSERT INTO J1_TBL VALUES (NULL, NULL, 'null');
|
|
INSERT INTO J1_TBL VALUES (NULL, 0, 'zero');
|
|
|
|
INSERT INTO J2_TBL VALUES (1, -1);
|
|
INSERT INTO J2_TBL VALUES (2, 2);
|
|
INSERT INTO J2_TBL VALUES (3, -3);
|
|
INSERT INTO J2_TBL VALUES (2, 4);
|
|
INSERT INTO J2_TBL VALUES (5, -5);
|
|
INSERT INTO J2_TBL VALUES (5, -5);
|
|
INSERT INTO J2_TBL VALUES (0, NULL);
|
|
INSERT INTO J2_TBL VALUES (NULL, NULL);
|
|
INSERT INTO J2_TBL VALUES (NULL, 0);
|
|
|
|
--
|
|
-- CORRELATION NAMES
|
|
-- Make sure that table/column aliases are supported
|
|
-- before diving into more complex join syntax.
|
|
--
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL AS tx;
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL tx;
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL AS t1 (a, b, c);
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL t1 (a, b, c);
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL t1 (a, b, c), J2_TBL t2 (d, e);
|
|
|
|
SELECT '' AS "xxx", t1.a, t2.e
|
|
FROM J1_TBL t1 (a, b, c), J2_TBL t2 (d, e)
|
|
WHERE t1.a = t2.d;
|
|
|
|
|
|
--
|
|
-- CROSS JOIN
|
|
-- Qualifications are not allowed on cross joins,
|
|
-- which degenerate into a standard unqualified inner join.
|
|
--
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL CROSS JOIN J2_TBL;
|
|
|
|
-- ambiguous column
|
|
SELECT '' AS "xxx", i, k, t
|
|
FROM J1_TBL CROSS JOIN J2_TBL;
|
|
|
|
-- resolve previous ambiguity by specifying the table name
|
|
SELECT '' AS "xxx", t1.i, k, t
|
|
FROM J1_TBL t1 CROSS JOIN J2_TBL t2;
|
|
|
|
SELECT '' AS "xxx", ii, tt, kk
|
|
FROM (J1_TBL CROSS JOIN J2_TBL)
|
|
AS tx (ii, jj, tt, ii2, kk);
|
|
|
|
SELECT '' AS "xxx", tx.ii, tx.jj, tx.kk
|
|
FROM (J1_TBL t1 (a, b, c) CROSS JOIN J2_TBL t2 (d, e))
|
|
AS tx (ii, jj, tt, ii2, kk);
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL CROSS JOIN J2_TBL a CROSS JOIN J2_TBL b;
|
|
|
|
|
|
--
|
|
--
|
|
-- Inner joins (equi-joins)
|
|
--
|
|
--
|
|
|
|
--
|
|
-- Inner joins (equi-joins) with USING clause
|
|
-- The USING syntax changes the shape of the resulting table
|
|
-- by including a column in the USING clause only once in the result.
|
|
--
|
|
|
|
-- Inner equi-join on specified column
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL INNER JOIN J2_TBL USING (i);
|
|
|
|
-- Same as above, slightly different syntax
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL JOIN J2_TBL USING (i);
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL t1 (a, b, c) JOIN J2_TBL t2 (a, d) USING (a)
|
|
ORDER BY a, d;
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL t1 (a, b, c) JOIN J2_TBL t2 (a, b) USING (b)
|
|
ORDER BY b, t1.a;
|
|
|
|
|
|
--
|
|
-- NATURAL JOIN
|
|
-- Inner equi-join on all columns with the same name
|
|
--
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL NATURAL JOIN J2_TBL;
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL t1 (a, b, c) NATURAL JOIN J2_TBL t2 (a, d);
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL t1 (a, b, c) NATURAL JOIN J2_TBL t2 (d, a);
|
|
|
|
-- mismatch number of columns
|
|
-- currently, Postgres will fill in with underlying names
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL t1 (a, b) NATURAL JOIN J2_TBL t2 (a);
|
|
|
|
|
|
--
|
|
-- Inner joins (equi-joins)
|
|
--
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL JOIN J2_TBL ON (J1_TBL.i = J2_TBL.i);
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL JOIN J2_TBL ON (J1_TBL.i = J2_TBL.k);
|
|
|
|
|
|
--
|
|
-- Non-equi-joins
|
|
--
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL JOIN J2_TBL ON (J1_TBL.i <= J2_TBL.k);
|
|
|
|
|
|
--
|
|
-- Outer joins
|
|
-- Note that OUTER is a noise word
|
|
--
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL LEFT OUTER JOIN J2_TBL USING (i)
|
|
ORDER BY i;
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL LEFT JOIN J2_TBL USING (i)
|
|
ORDER BY i;
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL RIGHT OUTER JOIN J2_TBL USING (i);
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL RIGHT JOIN J2_TBL USING (i);
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL FULL OUTER JOIN J2_TBL USING (i)
|
|
ORDER BY i, t;
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL FULL JOIN J2_TBL USING (i)
|
|
ORDER BY i, t;
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL LEFT JOIN J2_TBL USING (i) WHERE (k = 1);
|
|
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL LEFT JOIN J2_TBL USING (i) WHERE (i = 1);
|
|
|
|
|
|
--
|
|
-- More complicated constructs
|
|
--
|
|
|
|
-- UNION JOIN isn't implemented yet
|
|
SELECT '' AS "xxx", *
|
|
FROM J1_TBL UNION JOIN J2_TBL;
|
|
|
|
--
|
|
-- Multiway full join
|
|
--
|
|
|
|
CREATE TABLE t1 (name TEXT, n INTEGER);
|
|
CREATE TABLE t2 (name TEXT, n INTEGER);
|
|
CREATE TABLE t3 (name TEXT, n INTEGER);
|
|
|
|
INSERT INTO t1 VALUES ( 'aa', 11 );
|
|
INSERT INTO t2 VALUES ( 'aa', 12 );
|
|
INSERT INTO t2 VALUES ( 'bb', 22 );
|
|
INSERT INTO t2 VALUES ( 'dd', 42 );
|
|
INSERT INTO t3 VALUES ( 'aa', 13 );
|
|
INSERT INTO t3 VALUES ( 'bb', 23 );
|
|
INSERT INTO t3 VALUES ( 'cc', 33 );
|
|
|
|
SELECT * FROM t1 FULL JOIN t2 USING (name) FULL JOIN t3 USING (name);
|
|
|
|
--
|
|
-- Test interactions of join syntax and subqueries
|
|
--
|
|
|
|
-- Basic cases (we expect planner to pull up the subquery here)
|
|
SELECT * FROM
|
|
(SELECT * FROM t2) as s2
|
|
INNER JOIN
|
|
(SELECT * FROM t3) s3
|
|
USING (name);
|
|
|
|
SELECT * FROM
|
|
(SELECT * FROM t2) as s2
|
|
LEFT JOIN
|
|
(SELECT * FROM t3) s3
|
|
USING (name);
|
|
|
|
SELECT * FROM
|
|
(SELECT * FROM t2) as s2
|
|
FULL JOIN
|
|
(SELECT * FROM t3) s3
|
|
USING (name);
|
|
|
|
-- Cases with non-nullable expressions in subquery results;
|
|
-- make sure these go to null as expected
|
|
SELECT * FROM
|
|
(SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
|
|
NATURAL INNER JOIN
|
|
(SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3;
|
|
|
|
SELECT * FROM
|
|
(SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
|
|
NATURAL LEFT JOIN
|
|
(SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3;
|
|
|
|
SELECT * FROM
|
|
(SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
|
|
NATURAL FULL JOIN
|
|
(SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3;
|
|
|
|
SELECT * FROM
|
|
(SELECT name, n as s1_n, 1 as s1_1 FROM t1) as s1
|
|
NATURAL INNER JOIN
|
|
(SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
|
|
NATURAL INNER JOIN
|
|
(SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3;
|
|
|
|
SELECT * FROM
|
|
(SELECT name, n as s1_n, 1 as s1_1 FROM t1) as s1
|
|
NATURAL FULL JOIN
|
|
(SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
|
|
NATURAL FULL JOIN
|
|
(SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3;
|
|
|
|
SELECT * FROM
|
|
(SELECT name, n as s1_n FROM t1) as s1
|
|
NATURAL FULL JOIN
|
|
(SELECT * FROM
|
|
(SELECT name, n as s2_n FROM t2) as s2
|
|
NATURAL FULL JOIN
|
|
(SELECT name, n as s3_n FROM t3) as s3
|
|
) ss2;
|
|
|
|
SELECT * FROM
|
|
(SELECT name, n as s1_n FROM t1) as s1
|
|
NATURAL FULL JOIN
|
|
(SELECT * FROM
|
|
(SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
|
|
NATURAL FULL JOIN
|
|
(SELECT name, n as s3_n FROM t3) as s3
|
|
) ss2;
|
|
|
|
--
|
|
-- Clean up
|
|
--
|
|
|
|
DROP TABLE t1;
|
|
DROP TABLE t2;
|
|
DROP TABLE t3;
|
|
|
|
DROP TABLE J1_TBL;
|
|
DROP TABLE J2_TBL;
|