How to get rid of NOT EXISTS
-
10-12-2019 - |
Question
I have a sql that is not very complex but sufficiently confusion that I question rather I have an equivalent or by coincident that the count are the same.
SQL1:
SELECT a, b
FROM table1
WHERE NOT EXISTS(
SELECT a, c
FROM TABLE2
WHERE table2.a != table1.a)
SQL2
SELECT table1.a, table1.b
FROM table1
LEFT JOIN table2 ON table2.a = table1.a
WHERE table2.a IS NULL
The count on the two are identical, but not sure if this is by chance, and I want to make sure the conversion do not change the original functionality.
Solution
The first query, as you have it, returns all rows of TABLE1 where a
matches all values of a
in TABLE2. Therefore, it will return zero rows, unless there's a single not-null value for a
in TABLE2, and that value exists in TABLE1. In that case, it will return as many rows as there are in TABLE1 with that value of a
.
The second query is completely different. It will simply returns all rows of TABLE1 where a
does not exist in TABLE2.
So it's "matches all" (query 1) vs. "does not match any" (query 2). The fact that you are getting the same number of rows is pure coincidence.
Your queries would be equivalent if you changed !=
for =
in the first one, like this:
SELECT a, b
FROM table1
WHERE NOT EXISTS(
SELECT a, c
FROM TABLE2
WHERE table2.a = table1.a)
That gets you values of a
in table1 that doesn't exist in table2. This is EXACTLY the same as:
SELECT table1.a, b
FROM table1
LEFT JOIN table2 ON table2.a = table1.a
WHERE table2.a IS NULL
As you have it though, they are NOT equivalent. You must change !=
for =
in the first one to make them so.
OTHER TIPS
That doesn't look the same - but it's close. Your LEFT JOIN syntax is the same as:
SELECT a, b
FROM table1
WHERE NOT EXIST(
SELECT a, c
FROM TABLE2
WHERE table2.a = table1.a)
Note the "=" instead of "!=" though. Are you sure that's not what you have?
Your actual query translates to something like "where no non-matching rows exist", which would be odd, but could be expressed by changing the JOIN condition:
SELECT a, b
FROM table1
LEFT JOIN table2 ON table2.a != table1.a
WHERE table2.a IS NULL
For the first query i.e.
SELECT a, b
FROM table1
WHERE NOT EXISTS(
SELECT a, c
FROM TABLE2
WHERE table2.a != table1.a)
This will return all rows when all the values of a
in table1
are the same one value and either all the rows in table2
are the same one value as table1
or table2
is the empty set. Otherwise, the result will be the empty set.
The same cannot be same of your second query.
SELECT a, b, c , d
FROM table1 t1
WHERE NOT EXISTS( SELECT * FROM table2 nx
WHERE nx.y = t1.a
)
;
There is one big advantage of this ("correlated subquery") method: table table2 is not visible from the outside query, and cannot pollute it, or confuse your thinking. The subquery just produces one bit of information: either it exists, or does not exist. to be or not to be ....
In that respect, the LEFT JOIN idiom is nastier, since you'll have to check the xxx IS NULL
condition in the outer query, while the xxx references the table2 from the inner query.
Technically, there is no difference.