简体   繁体   中英

Find values missing in a column from a set (mysql)

I am using mysql.

I have a table that has a column id.

Let us say I have an input set of ids. I want to know which all ids are missing in the table.

If the set is "ida", "idb", "idc" and the table only contains "idb", then the returned value should be "ida", "idc".

Is this possible with a single sql query? If not, what is the most efficient way to execute this.

Note that I am not allowed to use stored procedure.

MySQL will only return rows that exist. To return missing rows you must have two tables.

The first table can be temporary (session/connection specific) so that multiple instances can run simultaneously.

create temporary table tmpMustExist (text id);
insert into tmpMustExist select "ida";
insert into tmpMustExist select "idb";
-- etc

select a.id from tmpMustExist as a
  left join table b on b.id=a.id
  where b.id is null; -- returns results from a table that are missing from b table.

Is this possible with a single sql query?

Well, yes it is. Let me work my way to that, first with a union all to combine the select statements.

create temporary table tmpMustExist (text id);
insert into tmpMustExist select "ida" union all select "idb" union all select "etc...";
select a.id from tmpMustExist as a left join table as b on b.id=a.id where b.id is null;

Note that I use union all which is a bit faster than union because it skips over deduplication.

You can use create table ... select . I do this frequently and really like it. (It is a great way to copy a table as well, but it will drop indexes.)

create temporary table tmpMustExist as select "ida" union all select "idb" union all select "etc...";
select a.id from tmpMustExist as a left join table as b on b.id=a.id where b.id is null;

And finally you can use what's called a "derived" table to bring the whole thing into a single, portable select statement.

select a.id from (select "ida" union all select "idb" union all select "etc...") as a left join table as b on b.id=a.id where b.id is null;

Note: the as keyword is optional, but clarifies what I'm doing with a and b . I'm simply creating short names to be used in the join and select field lists

//you can pass each set string to query
//pro-grammatically you can put quoted string
//columns must be utf8 collation

select * from
(SELECT 'ida' as col 
union  
SELECT 'idb' as col 
union  
SELECT 'idc' as col ) as setresult where col not in (SELECT value FROM `tbl`)

There's a trick. You can either create a table with expected values or you can use union of multiple select for each value.

Then you need to find all the values that are in the etalon, but not in the tested table.

CREATE TABLE IF NOT EXISTS `single` (
  `id` varchar(10) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `single` (`id`) VALUES
('idb');

SELECT a.id FROM (
   SELECT 'ida' as id
   UNION
   SELECT 'idb' as id
   UNION
   SELECT 'idc' AS id
) a WHERE a.id NOT IN (SELECT id FROM single)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM