Outer Joins

Started by Michael Dunnover 25 years ago22 messagesgeneral
Jump to latest
#1Michael Dunn
michael@2cactus.com

I am relatively new to the list and somewhat new to PostgreSQL. I am
wondering if there has been any discussion or thought about including
outer joins in later releases of PostreSQL. It seems highly inefficient
simulating outer joins with subqueries and UNION ALL statements. Or,
perhaps PostgreSQL has another way prevent unjoined rows from being
supressed in the results. Your comments are welcome.

Thanks, Micael Dunn

#2Poul L. Christiansen
poulc@cs.auc.dk
In reply to: Michael Dunn (#1)
Re: Outer Joins

PostgreSQL 7.1 (which is in beta now) will have outer joins.

It will probably (and hopefully) be released in Jan./Feb., but the beta
seems quite stable to me.

Poul L. Christiansen

Michael Dunn wrote:

Show quoted text

I am relatively new to the list and somewhat new to PostgreSQL. I am
wondering if there has been any discussion or thought about including
outer joins in later releases of PostreSQL. It seems highly inefficient
simulating outer joins with subqueries and UNION ALL statements. Or,
perhaps PostgreSQL has another way prevent unjoined rows from being
supressed in the results. Your comments are welcome.

Thanks, Micael Dunn

#3Gordan Bobic
gordan@freeuk.com
In reply to: Michael Dunn (#1)
Automatic on-line replication

Does postgres include this feature? Can someone point me toward the docs?

This is regarding the old clustering thread. If the on-line replication is
implemented, then it could be used for a form of clustering, because the
SELECTs could be distributed across multiple servers (one on each server).
Obviously, this would require the complete database to be on each server,
but until more advanced clustering methods are implemented, I don't see
another sensible way of doing clustering for situations where one server
just cannot feasibly cut it. Besides, insuring completeness of the returned
results when doing a multi-table join across multiple servers is a mind
numbingly hard problem...

I am also guessing that record locking would not work properly if multiple
computers were accessing the same physical database file that is mounted on
a remote file system. Is this the case? Not that I am even thinking about
trying to access data files via NFS or DFS... ;-)

Regards.

Gordan

#4Robert B. Easter
reaster@comptechnews.com
In reply to: Poul L. Christiansen (#2)
Re: Outer Joins

What is the syntax for this? Is there an example I can see/run?

On Thursday 04 January 2001 04:30, Poul L. Christiansen wrote:

PostgreSQL 7.1 (which is in beta now) will have outer joins.

It will probably (and hopefully) be released in Jan./Feb., but the beta
seems quite stable to me.

Poul L. Christiansen

Michael Dunn wrote:

I am relatively new to the list and somewhat new to PostgreSQL. I am
wondering if there has been any discussion or thought about including
outer joins in later releases of PostreSQL. It seems highly inefficient
simulating outer joins with subqueries and UNION ALL statements. Or,
perhaps PostgreSQL has another way prevent unjoined rows from being
supressed in the results. Your comments are welcome.

Thanks, Micael Dunn

--
-------- Robert B. Easter reaster@comptechnews.com ---------
-- CompTechNews Message Board http://www.comptechnews.com/ --
-- CompTechServ Tech Services http://www.comptechserv.com/ --
---------- http://www.comptechnews.com/~reaster/ ------------

#5Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert B. Easter (#4)
Re: Outer Joins

"Robert B. Easter" <reaster@comptechnews.com> writes:

What is the syntax for this? Is there an example I can see/run?

SQL92 standard.

See
http://www.postgresql.org/devel-corner/docs/postgres/sql-select.htm
for documentation (such as it is). There are some examples in the
join regression test, too.

regards, tom lane

#6Brett W. McCoy
bmccoy@chapelperilous.net
In reply to: Robert B. Easter (#4)
Re: Outer Joins

On Sat, 6 Jan 2001, Robert B. Easter wrote:

What is the syntax for this? Is there an example I can see/run?

Should follow standard SQL92 syntax (which, BTW, Oralce doesn't):

SELECT * FROM table1 LEFT OUTER JOIN table2 ON (table1.field =
table2.field)

This will return all rows from table1 even if no corresponding row exists
in table2. A RIGHT OUTER JOIN would do the opposite.

-- Brett
http://www.chapelperilous.net/~bmccoy/
---------------------------------------------------------------------------
It is better to have loved a short man than never to have loved a tall.

#7Robert B. Easter
reaster@comptechnews.com
In reply to: Tom Lane (#5)
Re: Outer Joins

On Saturday 06 January 2001 20:21, Tom Lane wrote:

"Robert B. Easter" <reaster@comptechnews.com> writes:

What is the syntax for this? Is there an example I can see/run?

SQL92 standard.

See
http://www.postgresql.org/devel-corner/docs/postgres/sql-select.htm
for documentation (such as it is). There are some examples in the
join regression test, too.

regards, tom lane

Thanks. I've tested out the cvs version and see that these joins appear to
work:

Qualified join:
T1 INNER|[LEFT|RIGHT|FULL OUTER] JOIN T2 ON|USING() ...

Natural join:
T1 NATURAL INNER|[LEFT|RIGHT|FULL OUTER] JOIN T2

Cross join:
T1 CROSS JOIN T2

But,

Union join:
T1 UNION JOIN T2

is not implemented. Nice! :)

Here is a sample running of all this on cvs pgsql:

CREATE TABLE a (id INTEGER, name TEXT, aname TEXT);
CREATE TABLE b (id INTEGER, name TEXT, bname TEXT);
CREATE TABLE c (id INTEGER, name TEXT, cname TEXT, date DATE DEFAULT
CURRENT_DATE);

INSERT INTO a VALUES (1, 'Bob', 'aname1');
INSERT INTO a VALUES (2, 'Jim', 'aname2');
INSERT INTO a VALUES (3, 'Tom', 'aname3');
INSERT INTO a VALUES (7, 'Joe', 'aname7');
INSERT INTO a VALUES (8, null, 'aname8');

INSERT INTO b VALUES (1, 'Bob', 'bname1');
INSERT INTO b VALUES (2, 'Tom', 'bname2');
INSERT INTO b VALUES (3, 'Joe', 'bname3');
INSERT INTO b VALUES (5, 'Jim', 'bname5');
INSERT INTO b VALUES (6, null, 'bname6');

INSERT INTO c VALUES (1, 'Bob', 'cname1');
INSERT INTO c VALUES (2, 'Jim', 'cname2');
INSERT INTO c VALUES (9, 'Tom', 'cname9');
INSERT INTO c VALUES (10, null, 'cname10');

-- Qualified Joins
SELECT * FROM a JOIN b USING (id) JOIN c USING (id);
SELECT * FROM a INNER JOIN b ON (a.id = b.id);
SELECT * FROM a LEFT OUTER JOIN b USING(id, name);
SELECT * FROM a RIGHT OUTER JOIN b USING (id);
SELECT * FROM a FULL OUTER JOIN b USING (id)
RIGHT OUTER JOIN c USING(id);
-- Natural Joins
SELECT * FROM a NATURAL INNER JOIN b;
SELECT * FROM a NATURAL LEFT OUTER JOIN b;
SELECT * FROM a NATURAL RIGHT OUTER JOIN b;
SELECT * FROM a NATURAL FULL OUTER JOIN b;
-- Cross Join
SELECT * FROM a CROSS JOIN b;
-- Union Join (not implemented, yet)
SELECT * FROM a UNION JOIN b;

The output is like this with cvs version:
--------------------------------------------------------

CREATE TABLE a (id INTEGER, name TEXT, aname TEXT);
CREATE
CREATE TABLE b (id INTEGER, name TEXT, bname TEXT);
CREATE
CREATE TABLE c (id INTEGER, name TEXT, cname TEXT, date DATE DEFAULT
CURRENT_DATE);
CREATE
INSERT INTO a VALUES (1, 'Bob', 'aname1');
INSERT 21117 1
INSERT INTO a VALUES (2, 'Jim', 'aname2');
INSERT 21118 1
INSERT INTO a VALUES (3, 'Tom', 'aname3');
INSERT 21118 1
INSERT INTO a VALUES (7, 'Joe', 'aname7');
INSERT 21119 1
INSERT INTO a VALUES (8, null, 'aname8');
INSERT 21120 1

INSERT INTO b VALUES (1, 'Bob', 'bname1');
INSERT 21121 1
INSERT INTO b VALUES (2, 'Tom', 'bname2');
INSERT 21122 1
INSERT INTO b VALUES (3, 'Joe', 'bname3');
INSERT 21122 1
INSERT INTO b VALUES (5, 'Jim', 'bname5');
INSERT 21122 1
INSERT INTO b VALUES (6, null, 'bname6');
INSERT 21123 1

INSERT INTO c VALUES (1, 'Bob', 'cname1');
INSERT 21124 1
INSERT INTO c VALUES (2, 'Jim', 'cname2');
INSERT 21125 1
INSERT INTO c VALUES (9, 'Tom', 'cname9');
INSERT 21126 1
INSERT INTO c VALUES (10, null, 'cname10');
INSERT 21127 1

SELECT * FROM a JOIN b USING (id) JOIN c USING (id);

id | name | aname | name | bname | name | cname | date
----+------+--------+------+--------+------+--------+------------
1 | Bob | aname1 | Bob | bname1 | Bob | cname1 | 2001-01-07
2 | Jim | aname2 | Tom | bname2 | Jim | cname2 | 2001-01-07
(2 rows)

SELECT * FROM a INNER JOIN b ON (a.id = b.id);

id | name | aname | id | name | bname
----+------+--------+----+------+--------
1 | Bob | aname1 | 1 | Bob | bname1
2 | Jim | aname2 | 2 | Tom | bname2
3 | Tom | aname3 | 3 | Joe | bname3
(3 rows)

SELECT * FROM a LEFT OUTER JOIN b USING(id, name);

id | name | aname | bname
----+------+--------+--------
1 | Bob | aname1 | bname1
2 | Jim | aname2 |
3 | Tom | aname3 |
7 | Joe | aname7 |
8 | | aname8 |
(5 rows)

SELECT * FROM a RIGHT OUTER JOIN b USING (id);

id | name | aname | name | bname
----+------+--------+------+--------
1 | Bob | aname1 | Bob | bname1
2 | Jim | aname2 | Tom | bname2
3 | Tom | aname3 | Joe | bname3
5 | | | Jim | bname5
6 | | | | bname6
(5 rows)

SELECT * FROM a FULL OUTER JOIN b USING (id)

id | name | aname | name | bname | name | cname | date
----+------+--------+------+--------+------+---------+------------
1 | Bob | aname1 | Bob | bname1 | Bob | cname1 | 2001-01-07
2 | Jim | aname2 | Tom | bname2 | Jim | cname2 | 2001-01-07
9 | | | | | Tom | cname9 | 2001-01-07
10 | | | | | | cname10 | 2001-01-07
(4 rows)

SELECT * FROM a NATURAL INNER JOIN b;

id | name | aname | bname
----+------+--------+--------
1 | Bob | aname1 | bname1
(1 row)

SELECT * FROM a NATURAL LEFT OUTER JOIN b;

id | name | aname | bname
----+------+--------+--------
1 | Bob | aname1 | bname1
2 | Jim | aname2 |
3 | Tom | aname3 |
7 | Joe | aname7 |
8 | | aname8 |
(5 rows)

SELECT * FROM a NATURAL RIGHT OUTER JOIN b;

id | name | aname | bname
----+------+--------+--------
1 | Bob | aname1 | bname1
2 | Tom | | bname2
3 | Joe | | bname3
5 | Jim | | bname5
6 | | | bname6
(5 rows)

SELECT * FROM a NATURAL FULL OUTER JOIN b;

id | name | aname | bname
----+------+--------+--------
1 | Bob | aname1 | bname1
2 | Jim | aname2 |
2 | Tom | | bname2
3 | Joe | | bname3
3 | Tom | aname3 |
5 | Jim | | bname5
6 | | | bname6
7 | Joe | aname7 |
8 | | aname8 |
(9 rows)

SELECT * FROM a CROSS JOIN b;

id | name | aname | id | name | bname
----+------+--------+----+------+--------
1 | Bob | aname1 | 1 | Bob | bname1
1 | Bob | aname1 | 2 | Tom | bname2
1 | Bob | aname1 | 3 | Joe | bname3
1 | Bob | aname1 | 5 | Jim | bname5
1 | Bob | aname1 | 6 | | bname6
2 | Jim | aname2 | 1 | Bob | bname1
2 | Jim | aname2 | 2 | Tom | bname2
2 | Jim | aname2 | 3 | Joe | bname3
2 | Jim | aname2 | 5 | Jim | bname5
2 | Jim | aname2 | 6 | | bname6
3 | Tom | aname3 | 1 | Bob | bname1
3 | Tom | aname3 | 2 | Tom | bname2
3 | Tom | aname3 | 3 | Joe | bname3
3 | Tom | aname3 | 5 | Jim | bname5
3 | Tom | aname3 | 6 | | bname6
7 | Joe | aname7 | 1 | Bob | bname1
7 | Joe | aname7 | 2 | Tom | bname2
7 | Joe | aname7 | 3 | Joe | bname3
7 | Joe | aname7 | 5 | Jim | bname5
7 | Joe | aname7 | 6 | | bname6
8 | | aname8 | 1 | Bob | bname1
8 | | aname8 | 2 | Tom | bname2
8 | | aname8 | 3 | Joe | bname3
8 | | aname8 | 5 | Jim | bname5
8 | | aname8 | 6 | | bname6
(25 rows)

SELECT * FROM a UNION JOIN b;

ERROR: UNION JOIN is not implemented yet
psql:/home/reaster/sql/join/join.sql:37: ERROR: UNION JOIN is not
implemented yet
--------------------------------------------------------

Just for the heck of it, I tried to execute all this sql on 7.0.3 and got
this:

jointest=# \i join2.sql
CREATE
CREATE
CREATE
INSERT 2836025 1
INSERT 2836026 1
INSERT 2836027 1
INSERT 2836028 1
INSERT 2836029 1
INSERT 2836030 1
INSERT 2836031 1
INSERT 2836032 1
INSERT 2836033 1
INSERT 2836034 1
INSERT 2836035 1
INSERT 2836036 1
INSERT 2836037 1
INSERT 2836038 1
psql:join2.sql:23: pqReadData() -- backend closed the channel unexpectedly.
This probably means the backend terminated abnormally
before or while processing the request.
psql:join2.sql:23: connection to server was lost

I knew it wouldn't run it, but didn't think it would crash.

--
-------- Robert B. Easter reaster@comptechnews.com ---------
-- CompTechNews Message Board http://www.comptechnews.com/ --
-- CompTechServ Tech Services http://www.comptechserv.com/ --
---------- http://www.comptechnews.com/~reaster/ ------------

#8Robert B. Easter
reaster@comptechnews.com
In reply to: Robert B. Easter (#7)
Re: Outer Joins

On Sunday 07 January 2001 00:53, Robert B. Easter wrote:

Union join:
T1 UNION JOIN T2

is not implemented. Nice! :)

[snip]

SELECT * FROM a UNION JOIN b;

ERROR: UNION JOIN is not implemented yet
psql:/home/reaster/sql/join/join.sql:37: ERROR: UNION JOIN is not
implemented yet

UNION JOIN is deprecated so maybe it doesn't need to be implemented?

--
-------- Robert B. Easter reaster@comptechnews.com ---------
-- CompTechNews Message Board http://www.comptechnews.com/ --
-- CompTechServ Tech Services http://www.comptechserv.com/ --
---------- http://www.comptechnews.com/~reaster/ ------------

#9Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert B. Easter (#7)
Re: Outer Joins

"Robert B. Easter" <reaster@comptechnews.com> writes:

Just for the heck of it, I tried to execute all this sql on 7.0.3 and got
this:
psql:join2.sql:23: pqReadData() -- backend closed the channel unexpectedly.
I knew it wouldn't run it, but didn't think it would crash.

7.0 had the beginnings of parser support for JOIN syntax, but there
were bugs ... I think the one that you hit had to do with nested JOIN
clauses, ie, a JOIN b JOIN c.

regards, tom lane

#10Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert B. Easter (#8)
Re: Outer Joins

"Robert B. Easter" <reaster@comptechnews.com> writes:

UNION JOIN is deprecated

Oh? By whom?

The reason 7.1 doesn't have it is I didn't have time for it, not that
we don't plan to do it ever.

regards, tom lane

#11Tom Lane
tgl@sss.pgh.pa.us
In reply to: Michael Dunn (#1)
Re: Outer Joins

"Robert B. Easter" <reaster@comptechnews.com> writes:

UNION JOIN is deprecated

Oh? By whom?

I read it in the SQL spec. ANSI/ISO 9075-2 1999 (final).

It is intended that the following features will be removed at a
later date from a revised version of this part of ISO/IEC 9075:
1) The ability to specify UNION JOIN in a <joined table> has been
deprecated.

Interesting. Maybe we won't ever bother to do it, then.

regards, tom lane

#12Robert B. Easter
reaster@comptechnews.com
In reply to: Tom Lane (#10)
Re: Outer Joins

On Sunday 07 January 2001 13:13, Tom Lane wrote:

"Robert B. Easter" <reaster@comptechnews.com> writes:

UNION JOIN is deprecated

Oh? By whom?

The reason 7.1 doesn't have it is I didn't have time for it, not that
we don't plan to do it ever.

I read it in the SQL spec. ANSI/ISO 9075-2 1999 (final).

Annex D

(informative)

Deprecated features

It is intended that the following features will be removed at a
later date from a revised version of this part of ISO/IEC 9075:

1) The ability to specify UNION JOIN in a <joined table> has been
deprecated.

It's the only one. I sent a patch to the patches list for JOIN
documentation. In it, the only thing I said about UNION JOIN is
"Deprecated." Let me know if I should change that. I thought about omitting
it entirely.

--
-------- Robert B. Easter reaster@comptechnews.com ---------
-- CompTechNews Message Board http://www.comptechnews.com/ --
-- CompTechServ Tech Services http://www.comptechserv.com/ --
---------- http://www.comptechnews.com/~reaster/ ------------

#13Gordan Bobic
gordan@freeuk.com
In reply to: Brett W. McCoy (#6)
Another optimizer question

I am not sure if this is a bug, an oversight or something else entirely,
but it would appear that if there are two tables, Table1 and Table2, which
are joined using INNER JOIN, specifying WHERE = one of the join fields
doesn't automatically get equalised to the other field.

For example:

SELECT * FROM Table1 INNER JOIN Table2 ON (Table1.Field1 = Table2.Field1)
WHERE Table1.Field1 = 'SomeValue';

takes a very long time (several minutes), and explain says that sequential
scans are used on both tables.

However, changing the above to:

SELECT * FROM Table1 INNER JOIN Table2 ON (Table1.Field1 = Table2.Field1)
WHERE Table1.Field1 = 'SomeValue' AND Table2.Field1 = 'SomeValue';

yields the correct answer in a fraction of a second. Explain says that
indices are being used. However, here's a REALLY strange thing. If I do:

SET ENABLE_SEQSCAN = OFF;

and run the first query, explain says that indices are used, but it STILL
takes forever. The first, slow query executes a merge join, while the
second only executes two index scans in a nested loop.

Why? This seems like a fairly basic thing, but it seems to break something
in the way the query is executed...

Regards.

Gordan

#14Tom Lane
tgl@sss.pgh.pa.us
In reply to: Gordan Bobic (#13)
Re: Another optimizer question

"Gordan Bobic" <gordan@freeuk.com> writes:

SELECT * FROM Table1 INNER JOIN Table2 ON (Table1.Field1 = Table2.Field1)
WHERE Table1.Field1 = 'SomeValue';
[ is slow, but this is fast: ]
SELECT * FROM Table1 INNER JOIN Table2 ON (Table1.Field1 = Table2.Field1)
WHERE Table1.Field1 = 'SomeValue' AND Table2.Field1 = 'SomeValue';

You're correct, we do not deduce the latter from the former, and so the
first example does not realize that it could use a constrained indexscan
over Table2.

Maybe we should try to do this, but I suspect we'd waste more cycles
trying than we'd make back on the queries where it helps.

regards, tom lane

#15Gordan Bobic
gordan@freeuk.com
In reply to: Brett W. McCoy (#6)
Re: Another optimizer question

SELECT * FROM Table1 INNER JOIN Table2 ON (Table1.Field1 =
Table2.Field1)
WHERE Table1.Field1 = 'SomeValue';
[ is slow, but this is fast: ]
SELECT * FROM Table1 INNER JOIN Table2 ON (Table1.Field1 =
Table2.Field1)
WHERE Table1.Field1 = 'SomeValue' AND Table2.Field1 = 'SomeValue';

You're correct, we do not deduce the latter from the former, and so the
first example does not realize that it could use a constrained indexscan
over Table2.

Maybe we should try to do this, but I suspect we'd waste more cycles
trying than we'd make back on the queries where it helps.

Hmm... As far as I can tell, it would help in any query joining several
tables on the same field in one table. I don't know how this compares to an
"average" case, but it is certainly common in the databases that I'm
working on... It would be nice if there was at least an option to enable
this sort of behaviour.

At the moment, the 6 table joins I am doing are so painfully slow, no
matter how I optimize the queries/views that I am going to forget about the
whole idea of views and set up some code that will do the separate table
subqueries manually. Even with _ALL_ fields that joins are performed on are
indexed in hash or btree, it still takes forever. Seen as I have to do this
often, unless I can find a way to speed up my queries by an order of
magnitude (or several in some cases), I don't see any other way around
this.

If I do a view that produces the data I want through joins, it takes hours,
even with all fields indexed, and after VACUUM ANALYZE. Doing SET ENABLE
SEQ_SCAN = OFF doesn't seem to make any difference. The query plan changes,
but select times are still roughly the same... Doing the separate
subqueries on each table and joining data manualy in the application code
takes literaly seconds. I am sure that cannot be right and I must be doing
something wrong, so if anyone has a good idea of how to solve this type of
problem, I'm not sure I have a lot of options left...

Regards.

Gordan

#16Tom Lane
tgl@sss.pgh.pa.us
In reply to: Gordan Bobic (#15)
Re: Another optimizer question

"Gordan Bobic" <gordan@freeuk.com> writes:

If I do a view that produces the data I want through joins, it takes hours,
even with all fields indexed, and after VACUUM ANALYZE. Doing SET ENABLE
SEQ_SCAN = OFF doesn't seem to make any difference. The query plan changes,
but select times are still roughly the same... Doing the separate
subqueries on each table and joining data manualy in the application code
takes literaly seconds.

Um, have you updated since I changed the subselect-restriction
processing two days ago?

regards, tom lane

#17Gordan Bobic
gordan@freeuk.com
In reply to: Brett W. McCoy (#6)
Re: Another optimizer question

If I do a view that produces the data I want through joins, it takes

hours,

even with all fields indexed, and after VACUUM ANALYZE. Doing SET

ENABLE

SEQ_SCAN = OFF doesn't seem to make any difference. The query plan

changes,

but select times are still roughly the same... Doing the separate
subqueries on each table and joining data manualy in the application

code

takes literaly seconds.

Um, have you updated since I changed the subselect-restriction
processing two days ago?

Not yet. I've done it in appliction code for now. I'll try again in
straight SQL when the next beta or release are available.

Thanks.

Gordan

#18Bruce Momjian
bruce@momjian.us
In reply to: Robert B. Easter (#7)
Re: Outer Joins

Can someone explain why cname and date from table c gets printed in this
query?

Thanks.

SELECT * FROM a FULL OUTER JOIN b USING (id)

id | name | aname | name | bname | name | cname | date
----+------+--------+------+--------+------+---------+------------
1 | Bob | aname1 | Bob | bname1 | Bob | cname1 | 2001-01-07
2 | Jim | aname2 | Tom | bname2 | Jim | cname2 | 2001-01-07
9 | | | | | Tom | cname9 | 2001-01-07
10 | | | | | | cname10 | 2001-01-07
(4 rows)

---------------------------------------------------------------------------

[ Charset ISO-8859-1 unsupported, converting... ]

On Saturday 06 January 2001 20:21, Tom Lane wrote:

"Robert B. Easter" <reaster@comptechnews.com> writes:

What is the syntax for this? Is there an example I can see/run?

SQL92 standard.

See
http://www.postgresql.org/devel-corner/docs/postgres/sql-select.htm
for documentation (such as it is). There are some examples in the
join regression test, too.

regards, tom lane

Thanks. I've tested out the cvs version and see that these joins appear to
work:

Qualified join:
T1 INNER|[LEFT|RIGHT|FULL OUTER] JOIN T2 ON|USING() ...

Natural join:
T1 NATURAL INNER|[LEFT|RIGHT|FULL OUTER] JOIN T2

Cross join:
T1 CROSS JOIN T2

But,

Union join:
T1 UNION JOIN T2

is not implemented. Nice! :)

Here is a sample running of all this on cvs pgsql:

CREATE TABLE a (id INTEGER, name TEXT, aname TEXT);
CREATE TABLE b (id INTEGER, name TEXT, bname TEXT);
CREATE TABLE c (id INTEGER, name TEXT, cname TEXT, date DATE DEFAULT
CURRENT_DATE);

INSERT INTO a VALUES (1, 'Bob', 'aname1');
INSERT INTO a VALUES (2, 'Jim', 'aname2');
INSERT INTO a VALUES (3, 'Tom', 'aname3');
INSERT INTO a VALUES (7, 'Joe', 'aname7');
INSERT INTO a VALUES (8, null, 'aname8');

INSERT INTO b VALUES (1, 'Bob', 'bname1');
INSERT INTO b VALUES (2, 'Tom', 'bname2');
INSERT INTO b VALUES (3, 'Joe', 'bname3');
INSERT INTO b VALUES (5, 'Jim', 'bname5');
INSERT INTO b VALUES (6, null, 'bname6');

INSERT INTO c VALUES (1, 'Bob', 'cname1');
INSERT INTO c VALUES (2, 'Jim', 'cname2');
INSERT INTO c VALUES (9, 'Tom', 'cname9');
INSERT INTO c VALUES (10, null, 'cname10');

-- Qualified Joins
SELECT * FROM a JOIN b USING (id) JOIN c USING (id);
SELECT * FROM a INNER JOIN b ON (a.id = b.id);
SELECT * FROM a LEFT OUTER JOIN b USING(id, name);
SELECT * FROM a RIGHT OUTER JOIN b USING (id);
SELECT * FROM a FULL OUTER JOIN b USING (id)
RIGHT OUTER JOIN c USING(id);
-- Natural Joins
SELECT * FROM a NATURAL INNER JOIN b;
SELECT * FROM a NATURAL LEFT OUTER JOIN b;
SELECT * FROM a NATURAL RIGHT OUTER JOIN b;
SELECT * FROM a NATURAL FULL OUTER JOIN b;
-- Cross Join
SELECT * FROM a CROSS JOIN b;
-- Union Join (not implemented, yet)
SELECT * FROM a UNION JOIN b;

The output is like this with cvs version:
--------------------------------------------------------

CREATE TABLE a (id INTEGER, name TEXT, aname TEXT);
CREATE
CREATE TABLE b (id INTEGER, name TEXT, bname TEXT);
CREATE
CREATE TABLE c (id INTEGER, name TEXT, cname TEXT, date DATE DEFAULT
CURRENT_DATE);
CREATE
INSERT INTO a VALUES (1, 'Bob', 'aname1');
INSERT 21117 1
INSERT INTO a VALUES (2, 'Jim', 'aname2');
INSERT 21118 1
INSERT INTO a VALUES (3, 'Tom', 'aname3');
INSERT 21118 1
INSERT INTO a VALUES (7, 'Joe', 'aname7');
INSERT 21119 1
INSERT INTO a VALUES (8, null, 'aname8');
INSERT 21120 1

INSERT INTO b VALUES (1, 'Bob', 'bname1');
INSERT 21121 1
INSERT INTO b VALUES (2, 'Tom', 'bname2');
INSERT 21122 1
INSERT INTO b VALUES (3, 'Joe', 'bname3');
INSERT 21122 1
INSERT INTO b VALUES (5, 'Jim', 'bname5');
INSERT 21122 1
INSERT INTO b VALUES (6, null, 'bname6');
INSERT 21123 1

INSERT INTO c VALUES (1, 'Bob', 'cname1');
INSERT 21124 1
INSERT INTO c VALUES (2, 'Jim', 'cname2');
INSERT 21125 1
INSERT INTO c VALUES (9, 'Tom', 'cname9');
INSERT 21126 1
INSERT INTO c VALUES (10, null, 'cname10');
INSERT 21127 1

SELECT * FROM a JOIN b USING (id) JOIN c USING (id);

id | name | aname | name | bname | name | cname | date
----+------+--------+------+--------+------+--------+------------
1 | Bob | aname1 | Bob | bname1 | Bob | cname1 | 2001-01-07
2 | Jim | aname2 | Tom | bname2 | Jim | cname2 | 2001-01-07
(2 rows)

SELECT * FROM a INNER JOIN b ON (a.id = b.id);

id | name | aname | id | name | bname
----+------+--------+----+------+--------
1 | Bob | aname1 | 1 | Bob | bname1
2 | Jim | aname2 | 2 | Tom | bname2
3 | Tom | aname3 | 3 | Joe | bname3
(3 rows)

SELECT * FROM a LEFT OUTER JOIN b USING(id, name);

id | name | aname | bname
----+------+--------+--------
1 | Bob | aname1 | bname1
2 | Jim | aname2 |
3 | Tom | aname3 |
7 | Joe | aname7 |
8 | | aname8 |
(5 rows)

SELECT * FROM a RIGHT OUTER JOIN b USING (id);

id | name | aname | name | bname
----+------+--------+------+--------
1 | Bob | aname1 | Bob | bname1
2 | Jim | aname2 | Tom | bname2
3 | Tom | aname3 | Joe | bname3
5 | | | Jim | bname5
6 | | | | bname6
(5 rows)

SELECT * FROM a FULL OUTER JOIN b USING (id)

id | name | aname | name | bname | name | cname | date
----+------+--------+------+--------+------+---------+------------
1 | Bob | aname1 | Bob | bname1 | Bob | cname1 | 2001-01-07
2 | Jim | aname2 | Tom | bname2 | Jim | cname2 | 2001-01-07
9 | | | | | Tom | cname9 | 2001-01-07
10 | | | | | | cname10 | 2001-01-07
(4 rows)

SELECT * FROM a NATURAL INNER JOIN b;

id | name | aname | bname
----+------+--------+--------
1 | Bob | aname1 | bname1
(1 row)

SELECT * FROM a NATURAL LEFT OUTER JOIN b;

id | name | aname | bname
----+------+--------+--------
1 | Bob | aname1 | bname1
2 | Jim | aname2 |
3 | Tom | aname3 |
7 | Joe | aname7 |
8 | | aname8 |
(5 rows)

SELECT * FROM a NATURAL RIGHT OUTER JOIN b;

id | name | aname | bname
----+------+--------+--------
1 | Bob | aname1 | bname1
2 | Tom | | bname2
3 | Joe | | bname3
5 | Jim | | bname5
6 | | | bname6
(5 rows)

SELECT * FROM a NATURAL FULL OUTER JOIN b;

id | name | aname | bname
----+------+--------+--------
1 | Bob | aname1 | bname1
2 | Jim | aname2 |
2 | Tom | | bname2
3 | Joe | | bname3
3 | Tom | aname3 |
5 | Jim | | bname5
6 | | | bname6
7 | Joe | aname7 |
8 | | aname8 |
(9 rows)

SELECT * FROM a CROSS JOIN b;

id | name | aname | id | name | bname
----+------+--------+----+------+--------
1 | Bob | aname1 | 1 | Bob | bname1
1 | Bob | aname1 | 2 | Tom | bname2
1 | Bob | aname1 | 3 | Joe | bname3
1 | Bob | aname1 | 5 | Jim | bname5
1 | Bob | aname1 | 6 | | bname6
2 | Jim | aname2 | 1 | Bob | bname1
2 | Jim | aname2 | 2 | Tom | bname2
2 | Jim | aname2 | 3 | Joe | bname3
2 | Jim | aname2 | 5 | Jim | bname5
2 | Jim | aname2 | 6 | | bname6
3 | Tom | aname3 | 1 | Bob | bname1
3 | Tom | aname3 | 2 | Tom | bname2
3 | Tom | aname3 | 3 | Joe | bname3
3 | Tom | aname3 | 5 | Jim | bname5
3 | Tom | aname3 | 6 | | bname6
7 | Joe | aname7 | 1 | Bob | bname1
7 | Joe | aname7 | 2 | Tom | bname2
7 | Joe | aname7 | 3 | Joe | bname3
7 | Joe | aname7 | 5 | Jim | bname5
7 | Joe | aname7 | 6 | | bname6
8 | | aname8 | 1 | Bob | bname1
8 | | aname8 | 2 | Tom | bname2
8 | | aname8 | 3 | Joe | bname3
8 | | aname8 | 5 | Jim | bname5
8 | | aname8 | 6 | | bname6
(25 rows)

SELECT * FROM a UNION JOIN b;

ERROR: UNION JOIN is not implemented yet
psql:/home/reaster/sql/join/join.sql:37: ERROR: UNION JOIN is not
implemented yet
--------------------------------------------------------

Just for the heck of it, I tried to execute all this sql on 7.0.3 and got
this:

jointest=# \i join2.sql
CREATE
CREATE
CREATE
INSERT 2836025 1
INSERT 2836026 1
INSERT 2836027 1
INSERT 2836028 1
INSERT 2836029 1
INSERT 2836030 1
INSERT 2836031 1
INSERT 2836032 1
INSERT 2836033 1
INSERT 2836034 1
INSERT 2836035 1
INSERT 2836036 1
INSERT 2836037 1
INSERT 2836038 1
psql:join2.sql:23: pqReadData() -- backend closed the channel unexpectedly.
This probably means the backend terminated abnormally
before or while processing the request.
psql:join2.sql:23: connection to server was lost

I knew it wouldn't run it, but didn't think it would crash.

--
-------- Robert B. Easter reaster@comptechnews.com ---------
-- CompTechNews Message Board http://www.comptechnews.com/ --
-- CompTechServ Tech Services http://www.comptechserv.com/ --
---------- http://www.comptechnews.com/~reaster/ ------------

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#19Tom Lane
tgl@sss.pgh.pa.us
In reply to: Bruce Momjian (#18)
Re: Outer Joins

Bruce Momjian <pgman@candle.pha.pa.us> writes:

Can someone explain why cname and date from table c gets printed in this
query?

Say what?

test=# CREATE TABLE a (id INTEGER, name TEXT, aname TEXT);
CREATE
test=# CREATE TABLE b (id INTEGER, name TEXT, bname TEXT);
CREATE
test=# CREATE TABLE c (id INTEGER, name TEXT, cname TEXT, date DATE DEFAULT
test(# CURRENT_DATE);
CREATE
test=# SELECT * FROM a FULL OUTER JOIN b USING (id);
id | name | aname | name | bname
----+------+-------+------+-------
(0 rows)

regards, tom lane

#20Bruce Momjian
bruce@momjian.us
In reply to: Tom Lane (#19)
Re: Outer Joins

Bruce Momjian <pgman@candle.pha.pa.us> writes:

Can someone explain why cname and date from table c gets printed in this
query?

Say what?

test=# CREATE TABLE a (id INTEGER, name TEXT, aname TEXT);
CREATE
test=# CREATE TABLE b (id INTEGER, name TEXT, bname TEXT);
CREATE
test=# CREATE TABLE c (id INTEGER, name TEXT, cname TEXT, date DATE DEFAULT
test(# CURRENT_DATE);
CREATE
test=# SELECT * FROM a FULL OUTER JOIN b USING (id);
id | name | aname | name | bname
----+------+-------+------+-------
(0 rows)

The text of the email showed this query returning columns from table c.
Seems it was just a mistake in the email.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#21Robert B. Easter
reaster@comptechnews.com
In reply to: Bruce Momjian (#18)
#22Erik Tennant
lists@webpd.com
In reply to: Tom Lane (#5)