MySQL query to find ids that do not exist in table - mysql

I have a list of ids pre-generated that I need to check if exist in a table. My table has two columns, id, name, where id is an auto increment integer and name is a varchar(255).
I basically want to get a count of how many ids do not exist in table foo from my pre-generated list. So say my list has the numbers 5 and 10 in it, what's the best way to write something to the extent of:
select count(*) from foo where id does not exist in ( 5, 10 )
The idea here is that if 5 and 10 do not exist, I need the response 2, and not the number of rows in foo that do not have the id 5 or 10.

TL; DR sample data and queries at rextester
The idea here is that if 5 and 10 do not exist, I need the response 2, and not the number of rows in foo that do not have the id 5 or 10.
You should have provided a little more information to avoid confusion.
Example
id | name
1 | tom
2 | joe
3 | mae
4 | goku
5 | vegeta
If your list contains (1, 2, 3) then your answer should be 0 (since all three are in the table )
If your list contains (1, 2, 6) then your answer should be 1. ( since 1 and 2 are in the table but 6 is in't )
If your list contains (1, 6, 7) then your answer should be 2.
If your list contains (6, 7, 8) then your answer should be 3.
assuming this was your question
If you know the length of your list
select 2 - count(*) as my_count from foo where id in (5, 10)
The following query tells you how many are present in foo.
select count(*) from foo where id in (5,10)
So if you want to find those that do not exist, subtract this result from the length of your list.
select n - count(*) as my_count from foo where id in (5, 10,....)

You could use on fly table using union and the a left join
select count(*)
from my_table as m
left join (
select 5 as id from dual
union
select 10 from dual ) t on t.id = m.id
where t.id is null
otherwise you can populate a tempo table with the value you need and use left join
where the value is null

Related

select group of rows that matches all its associated items to a list

I got a table:
id|name
------
1|Tom
1|Lucy
1|Frank
2|Lucy
2|Frank
3|Frank
4|Jane
5|Robert
6|John
Need result of id's where all the names associated with a specific id match to the list
The list is ('Lucy','Frank','Jane','Robert','Brandon').
I've tried this:
select id
from table
group by id
having name in('Lucy','Frank','Jane','Robert','Brandon')
Obtained result:
1
2
3
4
5
Desired Result:
2
3
4
5
What's excluded: the count(distinct id) > 2000
the list contains 200 names and each id is associated with at least 1 name
You can use aggregation, and a having clause that ensures that none of the names in the group does not belong to the list:
select id
from mytable
group by id
having max(name not in ('Lucy', 'Frank', 'Jane', 'Robert', 'Brandon')) = 0

Count first occurence with column value ordered by another column

I have an assigns table with the following columns:
id - int
id_lead - int
id_source - int
date_assigned - int (this represents a unix timestamp)
Now, lets say I have the following data in this table:
id id_lead id_source date_assigned
1 20 5 1462544612
2 20 6 1462544624
3 22 6 1462544615
4 22 5 1462544626
5 22 7 1462544632
6 25 6 1462544614
7 25 8 1462544621
Now, lets say I want to get a count of the rows whose id_source is 6, and is the first entry for each lead (sorted by date_assigned asc).
So in this case, the count would = 2, because there are 2 leads (id_lead 22 and 25) whose first id_source is 6.
How would I write this query so that it is fast and would work fine as a subquery select? I was thinking something like this which doesn't work:
select count(*) from `assigns` where `id_source`=6 order by `date_assigned` asc limit 1
I have no idea how to write this query in an optimal way. Any help would be appreciated.
Pseudocode:
select rows
with a.id_source = 6
but only if
there do not exist any row
with same id_lead
and smaller date_assigned
Translate it to SQL
select * -- select rows
from assigns a
where a.id_source = 6 -- with a.id_source = 6
and not exists ( -- but only if there do not exist any row
select 1
from assigns a1
where a1.id_lead = a.id_lead -- with same id_lead
and a1.date_assigned < a.date_assigned -- and smaller date_assigned
)
Now replace select * with select count(*) and you'll get your result.
http://sqlfiddle.com/#!9/3dc0f5/7
Update:
The NOT-EXIST query can be rewritten to an excluding LEFT JOIN query:
select count(*)
from assigns a
left join assigns a1
on a1.id_lead = a.id_lead
and a1.date_assigned < a.date_assigned
where a.id_source = 6
and a1.id_lead is null
If you want to get the count for all values of id_source, the folowing query might be the fastest:
select a.id_source, count(1)
from (
select a1.id_lead, min(a1.date_assigned) date_assigned
from assigns a1
group by a1.id_lead
) a1
join assigns a
on a.id_lead = a1.id_lead
and a.date_assigned = a1.date_assigned
group by a.id_source
You still can replace group by a.id_source with where a.id_source = 6.
The queries need indexes on assigns(id_source) and assigns(id_lead, date_assigned).
Simple query for that would be
check here http://sqlfiddle.com/#!9/8666e0/7
select count(*) from
(select * from assigns group by id_lead )t
where t.id_source=6

join with union of multiple tables in SQL

I have the following data structure:
a table entries with a column entry_id
a table data_int with columns entry_id, question and data
a table data_text with columns entry_id, question and data
a table questions with columns question_id
Now I would like to make a MySQL query that does the following: for a given entry_id (say 222) it should select all question_id q from that table for which there is no row with (entry_id=222 AND question_id=q) in data_int, and also no such row in data_text. Is this possible in a single query, and if so how should I do this?
A sample data set would be
entries:
1
2
data_int:
1, 1, 4
1, 2, 56
1, 6, 43
1, 7, -1
data_text:
1, 3, 'hello'
1, 5, 'world'
questions:
1
2
3
4
5
6
7
8
9
10
Then for entry_id=1, the return value should be 4, 8, 9, 10, since these don't appear in either data_ table for entry_id=1.
For entry_id=2, the return value should be 1,2,3,4,5,6,7,8,9,10 since nothing appears in any of the data_ tables.
There are a couple ways to do this. The more efficient way with mysql is probably using multiple outer join / null checks.
select q.*
from questions q
left join data_int di on q.questionid = di.questionid and di.entryid = 1
left join data_text dt on q.questionid = dt.questionid and dt.entryid = 1
where di.entryid is null and dt.entryid is null

Select From table name obtained dynamically from the query

I have 3 Tables
campaign1 (TABLE)
id campaign_details
1 'some detail'
campaign2 (TABLE)
id campaign_details
1 'some other detail'
campaign_list (TABLE)
id campaign_table_name
1 'campaign1'
2 'campaign2'
Campaign list table contains the table name of the two tables described above. I want to Select from the Campaign List table and get the record count using the table name i get from this select
For eg.
using select i get campaign1(Table name). Then i run select query on campaign1 to count number of records.
What i'm doing right now is .
-Select from campign_list
-loop through all campaign_table_names and run select query individually
Is there a way to do this using a single query
something like this
select campaign_name,(SELECT COUNT(*) FROM c.campaign_name) as campcount from campaign_list c
SQLFiddle : http://sqlfiddle.com/#!9/b766d/2
It's not possible inside a single query to build it dynamically but it's possible to cheat. Especially if there are only two linked tables.
I've listed two options
left outer join both tables
select campaign_name,
coalesce(c1.campaign_details, c2.campaign_details)
from campaign_list c
left join campaign1 c1 using (id)
left join campaign2 c2 using (id);
union all two different selects
select campaign_name,
campaign_details
from campaign_list c
join campaign1 c1 using (id)
union all
select campaign_name,
campaign_details
from campaign_list c
join campaign2 c2 using (id);
sqlfiddle
Combine your campaign tables to 1 table and add an column named 'type' (int).
campaign_items tables:
item_id item_details item_type
1 'some detail' 1
2 'some detail' 1
3 'some other detail' 2
4 'some other detail' 2
campaign_lists table
campaign_id campaign_name
1 'campaign1'
2 'campaign2'
Then you can use the following select statement:
SELECT campaign_name, (SELECT COUNT(*) FROM campaign_items WHERE item_type = campaign_id) as campaign_count
FROM campaign_lists
Oops, writing took me so long that you got this answered by Colin Raaijmakers already. Well, I'll post my answer anyway in spite of being more or less the same answer. Maybe my elaboration helps you see the problem.
Your problem stems from a bad database design. A database is made to order data and its relations. A CD database holds albums, songs, artists, etc. A business database may hold items, warehouses, sales and so on. Your database holds table names. [... time for thinking :-) ]
(When writing a DBMS you would want to store table names, column names, constraints etc., but I guess I am right supposing that you are not writing a new DBMS.)
So create tables that deal with your actual data. E.g.:
campain_type (id_campain_type, description, ...)
campain (id_campain, id_campain_type, campain_date, ...)
campain_type
id_campain_type description
1 Type A
2 Type B
3 Type C
campain
id_campain id_campain_type date
33 1 2015-06-03
85 2 2015-10-23
97 2 2015-12-01
query
select
ct.description,
(select count(*) from campain c where c.id_campain_type = ct.id_campain_type) as cnt
from campain_type ct;
result
description cnt
Type A 1
Type B 2
Type C 0

counting overlapping bitwise columns in mysql

I have a table in which there is a bitwise column representing a list of statuses that can be attached to an entry. Each entry can have multiple statuses selected (hence the use of the bitwise logic).
What I'd like to do is pull a query that will tell me how many entires there are for each status (i.e. how many times each bit is turned on). The difficulty I have is that there is of course overlap so a GROUP BY or a DISTINCT is not going to cut it (as far as I can see).
As an example let's just have two values, 1 and 2. and the following data
Id | Status
1 | 1
2 | 1
3 | 2
4 | 3
Now, I want to count how many entries there are for each bit so I'd like something that counts that 3 value into both the 1 and 2 totals, outputting something like this:
Bit | Count
1 | 3
2 | 2
The closest I can get so far seems to be pulling out the distinct values and then adding those with multiple entries into their corresponding counts using PHP. Obviously, I'd like to do something a bit more elegant.
Any ideas?
Expand the bits table as required
select `bit`, count(*) `count`
from bitt s
inner join (select 1 `bit` union all
select 2 union all
select 3 union all
select 4 union all
select 5) bits on s.status & Pow(2,bits.`bit`-1)
group by bits.`bit`
You could do:
SUM(IF(`Status`&1,1,0)) as `count1`,
SUM(IF(`Status`&2,1,0)) as `count2`,
SUM(IF(`Status`&4,1,0)) as `count4`
If you want to optimize it, you can still GROUP BY Status, but then you would need (a little) post-processing to sum the 8 rows you would get for a 3-bit situation.
One more variant -
SELECT 0, COUNT(IF(status >> 0 & 1 = 1, 1, NULL)) FROM table1
UNION
SELECT 1, COUNT(IF(status >> 1 & 1 = 1, 1, NULL)) FROM table1
UNION
SELECT 2, COUNT(IF(status >> 2 & 1 = 1, 1, NULL)) FROM table1
...