-4

So I'm learning SQL (sqlite flavour) and looking through the sqlite JOIN-clause documentation, I figure that these two statements are valid:

SELECT *
FROM table1
JOIN (table2, table3) USING (id);
SELECT *
FROM table1
JOIN table2 USING (id)
JOIN table3 USING (id)

(or even, but that's beside the point:

SELECT *
FROM table1
JOIN (table 2 JOIN table3 USING id) USING id

)

Now I've seen the second one (chained join) a lot in SO questions on JOIN clauses, but rarely the first (grouped table-query). Both querys execute in SQLiteStudio for the non-simplified case.

A minimal example is provided here based on this code

CREATE TABLE table1 (
    id     INTEGER PRIMARY KEY,
    field1 TEXT
)
WITHOUT ROWID;

CREATE TABLE table2 (
    id     INTEGER PRIMARY KEY,
    field2 TEXT
)
WITHOUT ROWID;

CREATE TABLE table3 (
    id     INTEGER PRIMARY KEY,
    field3 TEXT
)
WITHOUT ROWID;

INSERT INTO table1 (field1, id)
VALUES ('FOO0', 0),
       ('FOO1', 1),
       ('FOO2', 2),
       ('FOO3', 3);

INSERT INTO table2 (field2, id)
VALUES ('BAR0', 0),
       ('BAR2', 1),
       ('BAR3', 3);

INSERT INTO table3 (field3, id)
VALUES ('PIP0', 0),
       ('PIP1', 1),
       ('PIP2', 2);

SELECT *
FROM table1
JOIN (table2, table3) USING (id);

SELECT *
FROM table1
JOIN table2 USING (id)
JOIN table3 USING (id);

Could someone explain why one would use one over the other and if they are not equivalent for certain input data, provide an example? The first certainly looks cleaner (at least less redundant) to me.


INNER JOIN ON vs WHERE clause has been suggested as a possible duplicate. While it touches on the use of , as a join operator, I feel the questions and especially the answers are more focussed on the readability aspect and use of WHERE vs JOIN. My question is more about the general validity and possible differences in outcome (given the necessary input to induce the difference).

Xaser
  • 2,066
  • 2
  • 22
  • 45
  • 2
    Does this answer your question? [INNER JOIN ON vs WHERE clause](https://stackoverflow.com/questions/1018822/inner-join-on-vs-where-clause) – Shawn Apr 01 '20 at 07:17
  • 2
    The first one certainly isn't allowed by the SQL standard, and I think the last one is invalid standard SQL as well –  Apr 01 '20 at 07:23
  • What did you learn running examples? What is "not happy"? Please in code questions give a [mre]--cut & paste & runnable code, including smallest representative example input as code; desired & actual output (including verbatim error messages); tags & versions; clear specification & explanation. Give the least code you can give that is code that you show is OK extended by code that you show is not OK. (Debugging fundamental.) For SQL that includes DBMS & DDL (including constraints & indexes) & input as code formatted as a table. [ask] – philipxy Apr 01 '20 at 07:35
  • Edit your post to clearly ask the 1 specific question you are trying to ask. Please don't insert EDITs/UPDATEs, just make your post the best presentation as of editing time. Adding to something unclear doesn't make it clear. PS My answer already tells you where they are not equivalent--in the example you gave. But you haven't run that actual code. – philipxy Apr 01 '20 at 09:13
  • Added minimalistic example, which eliminates certain intrinsic assumptions made in the non-simplified example and reveals actual differences. I propose to close this question as I feel I cannot rephrase it in such a way that it becomes meaningful again. Thorsten's answer has been helpful but imo doesn't analyse the example provided in the question enough to justify an accept answer. – Xaser Apr 01 '20 at 10:17
  • Accept just means an answer helped the most. Why not indicate that? You can change your accept any time. – philipxy Apr 01 '20 at 11:25

2 Answers2

3

SQLite does not enforce a proper join syntax. It sees the join operator ([INNER] JOIN, LEFT [OUTER] JOIN, etc., even the comma of the outdated 1980s join syntax) separate from the condition (ON, USING). That is not good, because it makes joins more prone to errors. The SQLite docs are hence a very bad reference for learning joins. (And SQLite itself a bad system for learning them, because the DBMS doesn't detect standard SQL join violations.)

Stick to the syntax defined by the SQL standard (and don't ever use comma-separated joins):

FROM table [alias]

((([INNER] | [(LEFT|FULL) [OUTER]]) JOIN table [alias] (ON conditions | USING ( columns ))) | (CROSS JOIN table [alias]))

((([INNER] | [(LEFT|FULL) [OUTER]]) JOIN table [alias] (ON conditions | USING ( columns ))) | (CROSS JOIN table [alias]))

...

(Hope, I've got this right :-) And I also hope this is readable enough :-| I've omitted NATURAL JOIN and RIGHT [OUTER] JOIN here, because I don't recommend using them at all.)

For table you can place some table name or view or a subquery (the latter including parentheses, e.g. (select * from mytable)). Columns in USING have to be surrounded by parentheses (e.g. USING (a, b, c)). (You can of couse use parentheses around ON conditions as well, if you find this more readable.)

In your case, a properly written query would be:

SELECT *
FROM table1
JOIN table2 USING (id)
JOIN table3 USING (id)

or

SELECT *
FROM table1 t1
JOIN table2 t2 ON t2.id = t1.id
JOIN table3 t3 ON t3.id = t1.id

for instance. The example suggests three 1:1 related tables, though. In real life these are extremely rare and a more typical example would be

SELECT *
FROM table1 t1
JOIN table2 t2 ON t2.t1_id = t1.id
JOIN table3 t3 ON t3.t2_id = t2.id
Xaser
  • 2,066
  • 2
  • 22
  • 45
Thorsten Kettner
  • 89,309
  • 7
  • 49
  • 73
-4

After fixing syntax, these are not the same for all tables, read the syntax & definitions of the join operators in the manual. Comma is cross join with lower precedence than join keyword joins. Different DBMS's SQLs have syntax variations. Read the manual. Some allow naked join for cross join.

using returns only one column for each specified column name & natural is using for all common columns; but other joins are based on cross join & return a column for every input column. So since here tables 2 & 3 have id columns the comma returns a table with 2 id columns. Then using (id) doesn't make sense since one operand has 2 id columns.

If only tables 1 & 3 have an id column, clearly the 2nd query can't join 1 & 2 using id.

There are always many ways to express things. In particular SQL DBMSs execute many different expressions the same way. Research re relational query implementation/optimization in general, in SQL & in your DBMS manual. Generally no simple query variations like these make a difference in execution for the simplest query engine. (We see that in SQLite cross join "is handled differently by the query optimizer".)

First learn to write straightforward queries & learn what the operators do & what their syntax & restrictions are.

philipxy
  • 14,867
  • 6
  • 39
  • 83
  • Why does the syntax need fixing? 1st and 2nd snippets are compliant with the flow diagrams in the sqlite manual and execute fine. - Sqlite manual does not mention precedence of comma join. - Can you provide an example where execution is not the same (ideally in sqlite-flavour). – Xaser Apr 01 '20 at 09:11
  • It's correct that `(table1, table2)` will contain two (identical) id columns, but the first (again, at least in sqlite), will retain it's original name, i.e. `using id` will work fine. – Xaser Apr 01 '20 at 09:12
  • (edited) Your code is not compliant, using is followed by a left paren. And if you claim it "will work fine", give a [mre] we can cut & paste & run. The MySQL documentation says only one column is kept, so if the code runs, it isn't because there is a "first", and your reasons are not justfied. PS Re cases where the queries differ, see my edit. – philipxy Apr 01 '20 at 09:41
  • Thanks for clarifying and please see my comment in the question post. Nevertheless, your answer is not concise enough to accept as answer (mentions of manuals without reference, seemingly unrelated bits of information (.. naked join..), examples violating basic assumptions (id columns exist). – Xaser Apr 01 '20 at 10:19
  • My post adresses syntax, then 2 ways the queries differ, then addresses preference. So I can't agree re "unrelated bits". Re references, until someone gives a [mre] & looks up & applies the manual I'm not much interested in doing it either. That obligatory effort belongs in a question, see my comments on the question. Also this isn't a language lawyer question. The reason I moved my comments into an answer is that there aren't many questions for people to find re USING. Good luck. – philipxy Apr 01 '20 at 11:20
  • You might be interested in [this re non-outer joins](https://stackoverflow.com/a/25957600/3404097). Note that AND is commutative so JOINs, ON, WHERE & (per its definition) USING all get mapped to AND in the predicate/criterion for a query's rows. And AND is commutative--its operand order doesn't matter. Plus USING's operands must have the given columns. Plus SQLite accepts certain non-standard SQL with & without documentation. [Re SQL & relational querying.](https://stackoverflow.com/a/33952141/3404097) – philipxy Apr 01 '20 at 23:29