I have a list of values, say 1,2,3,4,5,6
. I have a SQL table with a field storing these values but only three rows, say, 2,4,5
. What sort of query will return three rows 1,3,6
for me? (storing all six in another table and left join'ing is cheating.)
Asked
Active
Viewed 1.6k times
6

chx
- 11,270
- 7
- 55
- 129
-
2Storing all the values in a lookup table and joining is by far the best way to do this. – HLGEM Jul 16 '12 at 19:14
-
Please include the type of datasbase you are on, the table structure and the SQL query that is returning three rows. – John D Jul 16 '12 at 19:15
-
1You mean like an antijoin or a `NOT IN()` clause? – Jeremy Holovacs Jul 16 '12 at 19:17
-
the answer that worked for me is here: http://stackoverflow.com/questions/10013475/select-that-returns-list-of-values-not-occurring-in-any-row#answer-27053607 – knocte Dec 18 '15 at 05:08
6 Answers
8
You didn't state your DBMS, so this is the ANSI SQL Version:
with the_values (id) as (
values (1),(2),(3),(4),(5),(6)
)
select v.id
from the_values v
left join the_real_table t on t.id = v.id
where t.id is null;
-
-
-
Op said left joining is "cheating" whatever that means. Didn't know we were taking an exam. ;) – sam yi Jul 16 '12 at 19:22
-
@samyi: actually it says "*storing in a temp table **and** left joining*" is cheating. But I'm not storing them in a temp table so the boolean expression is still true ;) – Jul 16 '12 at 19:24
-
The syntax doesn't work in SQL Server 2008, but something similar does. – Gordon Linoff Jul 16 '12 at 19:27
-
@GordonLinoff: yes SQL Server does not support the `values` row constructor. You would need to use a `SELECT 1 UNION ALL SELECT 2 ...` – Jul 16 '12 at 19:30
-
1I am a little torn on which answer to accept -- this is ANSI but doesn't work with MySQL and to get it working on SQL Server you need the `SELECT - UNION` construct and if you write that out then it's easier to `JOIN` on that construct without using `WITH`. Sounds like `WITH` is SQL'99 btw http://stackoverflow.com/questions/324935/mysql-with-clause – chx Jul 16 '12 at 22:49
-
@chx: the syntax works in PostgreSQL, HSQLDB, Teradata, Vertica and DB2. You should have mentioned that you are limited by MySQL in your question. – Jul 17 '12 at 06:46
-
Sorry about that -- I need a solution that works on MySQL *and* a wide range of databases. – chx Jul 17 '12 at 08:07
-
@chx: the accepted solution won't work on all databases either (e.g. Oracle, DB2, Firebird) as they don't allow a SELECT without a table. – Jul 17 '12 at 08:20
-
-
3
You could also try using EXCEPT (similar to MINUS in Oracle):
(SELECT 1
UNION
SELECT 2
UNION
SELECT 3
UNION
SELECT 4
UNION
SELECT 5
UNION
SELECT 6)
EXCEPT
(SELECT 2
UNION
SELECT 3
UNION
SELECT 4)
Or, more relevant to your example:
(SELECT 1
UNION
SELECT 2
UNION
SELECT 3
UNION
SELECT 4
UNION
SELECT 5
UNION
SELECT 6)
EXCEPT
(SELECT Field FROM Table)
where Field contains 2, 4, and 5.

TelJanini
- 835
- 9
- 25
-
That's a great idea. Here's a slight modification, one that works even in MySQL: `SELECT missing.1 AS missing FROM test RIGHT JOIN (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6) x ON x.1 = test.foo WHERE foo IS NULL;` – chx Jul 16 '12 at 22:46
-
Nice solution. For databases that support the `values` row constructor this could be shortened to `values (1),(2),(3),(4),(5),(6) EXCEPT SELECT col FROM foo` – Jul 17 '12 at 06:52
-
You mention that my query won't work on Oracle/DB2/Firebird -- would `SELECT missing.1 AS missing FROM test RIGHT JOIN (values (1),(2),(3),(4),(5),(6))...` work there? – chx Jul 17 '12 at 08:33
-
@chx that doesn't work in MySQL, it gives `Unknown column 'missing.1' in 'field list'` – knocte Dec 18 '15 at 04:53
-
this works for MySQL: http://stackoverflow.com/questions/10013475/select-that-returns-list-of-values-not-occurring-in-any-row#answer-27053607 – knocte Dec 18 '15 at 06:42
1
The not in
operator will do the check you want.
declare @allValues table (value int)
insert @allValues values (1)
insert @allValues values (2)
insert @allValues values (3)
insert @allValues values (4)
insert @allValues values (5)
insert @allValues values (6)
declare @someValues table (value int)
insert @someValues values (2)
insert @someValues values (4)
insert @someValues values (5)
select
*
from
@allValues
where
value not in (select value from @someValues)
Another method which is probably faster, using joins:
select
av.value
from
@allValues av
left join @someValues sv on (av.value = sv.value)
where
sv.value is null

tenfour
- 36,141
- 15
- 83
- 142
0
It's not cheating if it does the job. Set up a temp table or table variable with all the possible rows, then use a WHERE NOT EXISTS or a LEFT OUTER JOIN combined with WHERE TableVariableID IS NULL.

KeithS
- 70,210
- 21
- 112
- 164
-
It doesn't do the job for the simple reason that I don't have permissions to create a temporary table... What I have is basic select access to a very large table and an arbitrary list of a couple hundred external IDs and I need to figure out which ones don't have any entries in that table. (The list is coming from a completely external source -- if they don't exist in that table they don't exist at all in the db.) I ended up selecting out the ones that did exist and then using Excel and a tedious manual process. – user3067860 Jun 01 '22 at 14:27
0
with Mysql 8 you can use JSON_TABLE and select table from JSON array of values
SELECT *
FROM
JSON_TABLE(
'[1,2,3,4,5,6]',
'$[*]' COLUMNS( id INT PATH '$' ERROR ON ERROR )
) as v
left join the_real_table t on t.id = v.id
where t.id is null;

Adam Mátl
- 116
- 4
-3
You could use a NOT IN
clause.
SELECT column FROM table WHERE column NOT IN (2,4,5)

Marcus Recck
- 5,075
- 2
- 16
- 26