First, there was the SQL89 JOIN, where there was no JOIN statement, and joins were performed by adding WHERE clauses. To wit:
SELECT users.name, count(*)
FROM users, comments
WHERE users.user_id = comments.user_id
AND users.status = 'active'
AND comments.comment_date BETWEEN '2013-07-01' and '2013-07-31'
GROUP BY users.name;
There were two problems with this kind of JOIN: you often got join conditions mixed up with other filters and accidentally did cartesian products, and there was no way to do directional (outer) joins.
Not that that keeps people from continuing to use it.
So then we got the SQL92 JOIN:
SELECT users.name, count(*)
FROM users JOIN comments
ON users.user_id = comments.user_id
AND users.status = 'active'
AND comments.comment_date BETWEEN '2013-07-01' and '2013-07-31'
GROUP BY users.name;
But this wasn't the end of things. Since SQL92 allowed users to define FOREIGN KEYS, why not allow them to just join along the keys "naturally"?
SELECT users.name, count(*)
FROM users NATURAL JOIN comments
AND users.status = 'active'
AND comments.comment_date BETWEEN '2013-07-01' and '2013-07-31'
GROUP BY users.name;
Except that the SQL committee screwed up, and instead of using the declared foreign keys, NATURAL JOIN looks for columns with identical names. And if there are several columns with identical names, there's no standard way to resolve them. So, NATURAL JOIN, which ought to have been a real keyboard-saver, instead turned out to be uselessly unreliable.
One of the annoying issues about joins between two tables on columns of the same name is that SQL wants you to constantly qualify which table you're asking for the column from, even though the contents are identical:
ERROR: column reference "user_id" is ambiguous
This was annoying, so they created the USING clause instead:
SELECT user_id, users.name, count(*)
FROM users JOIN comments USING ( user_id )
AND users.status = 'active'
AND comments.comment_date BETWEEN '2013-07-01' and '2013-07-31'
GROUP BY user_id, users.name;
In Postgres, NATURAL JOIN also conflates matching columns, but it doesn't do this on all DBMSes.
Of course, USING only works if your columns do have the same names. All the more reason to adopt that as a naming convention!
SELECT users.name, count(*)
FROM users, comments
WHERE users.user_id = comments.user_id
AND users.status = 'active'
AND comments.comment_date BETWEEN '2013-07-01' and '2013-07-31'
GROUP BY users.name;
There were two problems with this kind of JOIN: you often got join conditions mixed up with other filters and accidentally did cartesian products, and there was no way to do directional (outer) joins.
Not that that keeps people from continuing to use it.
So then we got the SQL92 JOIN:
SELECT users.name, count(*)
FROM users JOIN comments
ON users.user_id = comments.user_id
AND users.status = 'active'
AND comments.comment_date BETWEEN '2013-07-01' and '2013-07-31'
GROUP BY users.name;
But this wasn't the end of things. Since SQL92 allowed users to define FOREIGN KEYS, why not allow them to just join along the keys "naturally"?
SELECT users.name, count(*)
FROM users NATURAL JOIN comments
AND users.status = 'active'
AND comments.comment_date BETWEEN '2013-07-01' and '2013-07-31'
GROUP BY users.name;
Except that the SQL committee screwed up, and instead of using the declared foreign keys, NATURAL JOIN looks for columns with identical names. And if there are several columns with identical names, there's no standard way to resolve them. So, NATURAL JOIN, which ought to have been a real keyboard-saver, instead turned out to be uselessly unreliable.
One of the annoying issues about joins between two tables on columns of the same name is that SQL wants you to constantly qualify which table you're asking for the column from, even though the contents are identical:
ERROR: column reference "user_id" is ambiguous
This was annoying, so they created the USING clause instead:
SELECT user_id, users.name, count(*)
FROM users JOIN comments USING ( user_id )
AND users.status = 'active'
AND comments.comment_date BETWEEN '2013-07-01' and '2013-07-31'
GROUP BY user_id, users.name;
In Postgres, NATURAL JOIN also conflates matching columns, but it doesn't do this on all DBMSes.
Of course, USING only works if your columns do have the same names. All the more reason to adopt that as a naming convention!