MySQL SELECT EXISTS on Multiple Values - mysql

I believe this should be relatively simple but I can't seem to figure out the logic to it.
I'll start with what I'm looking for. I wanted to be able to pass in values (such as e-mail addresses) through a SELECT query and have it output whether those rows exist or not. It would be something like this:
# PASS Values test#test.com and example#example.com in.
# For these purposes let's pretend that test#test.com exists
# and example#example.com does not.
+----------------------+--------+
| E-mail | Exists |
+----------------------+--------+
| test#test.com | 1 |
| example#example.com | 0 |
+----------------------+--------+
There is the answer here for a single result: MySQL EXISTS return 1 or 0 but I would like to expand on that and am having issues figuring it out.
Any help would be great. Thanks!

Assuming I'm understanding your question correctly, you can't do this with in alone. One option is to create a subquery with an outer join, and then use case:
select t.email,
case when yt.email is not null then 1 else 0 end `exists`
from (select 'test#test.com' as email union all select 'example#example.com') t
left join yourtable yt on t.email = yt.email
Note: backticks are needed on exists in the statement.

Related

MYSQL, Include Null Results

Want a null row where no data exist
Hello. This is in regards to MySQL Workbench 6.3.
I'm trying to return a list of results for every item listed in my select statement, which would include those items that don't actually exist. So if i list 5 items in my select statement and only 3 exist, i'd like to get 5 rows returned, 3 actual rows with data and 2 more rows that only show null. Can someone please show me how to edit my query below to show this ? Thank you !
select emails from table where email in (dog, frog, cat, tiger, lizard);
Actual Result (only the 3 emails that actual exist show)
dog
cat
tiger
Desired Result
dog
null
cat
tiger
null
The desired results are not possible.. You can't expect MySQL to
return the selected records in the order they went in the IN()
operator.
So i think you better off when you change the desired result to something you know sometiming was not found in the table, i think you are looking for.
Query
SELECT
search_emails.email
, (
CASE
WHEN t.email IS NOT NULL
THEN 'true' ELSE 'false'
END
) AS found
FROM (
SELECT 'dog' AS email
UNION
SELECT 'frog' AS email
UNION
SELECT 'cat' AS email
UNION
SELECT 'tiger' AS email
UNION
SELECT 'lizard' AS email
) AS search_emails
LEFT JOIN
t
ON
t.email = search_emails.email
Result
| email | found |
| ------ | ----- |
| dog | true |
| cat | true |
| tiger | true |
| frog | false |
| lizard | false |
see demo
select emails from table where email in (dog, frog, cat, tiger, lizard) OR email IS NULL
be sure that the values provided for IN (...) are provided as strings.

SQL, table join wont display proper output [duplicate]

I've got the following two tables (in MySQL):
Phone_book
+----+------+--------------+
| id | name | phone_number |
+----+------+--------------+
| 1 | John | 111111111111 |
+----+------+--------------+
| 2 | Jane | 222222222222 |
+----+------+--------------+
Call
+----+------+--------------+
| id | date | phone_number |
+----+------+--------------+
| 1 | 0945 | 111111111111 |
+----+------+--------------+
| 2 | 0950 | 222222222222 |
+----+------+--------------+
| 3 | 1045 | 333333333333 |
+----+------+--------------+
How do I find out which calls were made by people whose phone_number is not in the Phone_book? The desired output would be:
Call
+----+------+--------------+
| id | date | phone_number |
+----+------+--------------+
| 3 | 1045 | 333333333333 |
+----+------+--------------+
There's several different ways of doing this, with varying efficiency, depending on how good your query optimiser is, and the relative size of your two tables:
This is the shortest statement, and may be quickest if your phone book is very short:
SELECT *
FROM Call
WHERE phone_number NOT IN (SELECT phone_number FROM Phone_book)
alternatively (thanks to Alterlife)
SELECT *
FROM Call
WHERE NOT EXISTS
(SELECT *
FROM Phone_book
WHERE Phone_book.phone_number = Call.phone_number)
or (thanks to WOPR)
SELECT *
FROM Call
LEFT OUTER JOIN Phone_Book
ON (Call.phone_number = Phone_book.phone_number)
WHERE Phone_book.phone_number IS NULL
(ignoring that, as others have said, it's normally best to select just the columns you want, not '*')
SELECT Call.ID, Call.date, Call.phone_number
FROM Call
LEFT OUTER JOIN Phone_Book
ON (Call.phone_number=Phone_book.phone_number)
WHERE Phone_book.phone_number IS NULL
Should remove the subquery, allowing the query optimiser to work its magic.
Also, avoid "SELECT *" because it can break your code if someone alters the underlying tables or views (and it's inefficient).
The code below would be a bit more efficient than the answers presented above when dealing with larger datasets.
SELECT *
FROM Call
WHERE NOT EXISTS (
SELECT 'x'
FROM Phone_book
WHERE Phone_book.phone_number = Call.phone_number
);
SELECT DISTINCT Call.id
FROM Call
LEFT OUTER JOIN Phone_book USING (id)
WHERE Phone_book.id IS NULL
This will return the extra id-s that are missing in your Phone_book table.
I think
SELECT CALL.* FROM CALL LEFT JOIN Phone_book ON
CALL.id = Phone_book.id WHERE Phone_book.name IS NULL
SELECT t1.ColumnID,
CASE
WHEN NOT EXISTS( SELECT t2.FieldText
FROM Table t2
WHERE t2.ColumnID = t1.ColumnID)
THEN t1.FieldText
ELSE t2.FieldText
END FieldText
FROM Table1 t1, Table2 t2
SELECT name, phone_number FROM Call a
WHERE a.phone_number NOT IN (SELECT b.phone_number FROM Phone_book b)
Alternatively,
select id from call
minus
select id from phone_number
Don't forget to check your indexes!
If your tables are quite large you'll need to make sure the phone book has an index on the phone_number field. With large tables the database will most likely choose to scan both tables.
SELECT *
FROM Call
WHERE NOT EXISTS
(SELECT *
FROM Phone_book
WHERE Phone_book.phone_number = Call.phone_number)
You should create indexes both Phone_Book and Call containing the phone_number. If performance is becoming an issue try an lean index like this, with only the phone number:
The fewer fields the better since it will have to load it entirely. You'll need an index for both tables.
ALTER TABLE [dbo].Phone_Book ADD CONSTRAINT [IX_Unique_PhoneNumber] UNIQUE NONCLUSTERED
(
Phone_Number
)
WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ONLINE = ON) ON [PRIMARY]
GO
If you look at the query plan it will look something like this and you can confirm your new index is actually being used. Note this is for SQL Server but should be similar for MySQL.
With the query I showed there's literally no other way for the database to produce a result other than scanning every record in both tables.

COALESCE and IFNULL not working as expected

I'm trying to output a default row when there's no row found in the query.
This is a sample of my query:
SELECT
COALESCE(site, 'STE') as site,
instrument,
field
FROM Table1
WHERE site IN ('East', 'West')
AND DATE(tstamp) = "2016-09-07"
ORDER BY id desc
The output is
+------+------------+-------+
| site | instrument | field |
+------+------------+-------+
| West | 0 | 0 |
+------+------------+-------+
For the tsamp 2016-09-07 we have a row for the site "West" and there's no row for "East". I tried to search and found that I can use COALESCE and also tried IFNULL but I'm only getting the output above. I also tried if(count(site) = 0, "STE", site) but i can't get it to work.
My expected result is
+------+------------+-------+
| site | instrument | field |
+------+------------+-------+
| West | 0 | 0 |
| STE | NULL | NULL |
+------+------------+-------+
I hope you guys can help me. Thanks in advance
Both coalesce() and ifnull() work on a row basis, meaning they can replace a null value if that null value exists in a record. However, they cannot create a record that does not exist - and you do not have any records matching East (or STE).
A possible solution is to create a table that has all possible values for the site field and you can left join on this table:
SELECT
COALESCE(Table1.site, "STE") as site,
Table1.instrument,
Table1.field
FROM LookupTable lt
LEFT JOIN Table1 ON lt.site=Table1.site
WHERE lt.site IN ('East', 'West')
AND DATE(Table1.tstamp) = "2016-09-07"
ORDER BY id desc
If 'STE' isn't in table1.site then it won't come back in the results.
You could do a union instead:
SELECT
site,
instrument,
field
FROM (SELECT 'West' [Site], 0 [instrument], 0 [field]) table1
WHERE site IN ('East', 'West')
UNION
SELECT 'STE', NULL, NULL
Note that by using "STE" you're looking for the column name "STE", not the value 'STE' (single quotes)
EDIT
You need a control table to dictate which values to look for, or you have to hard code your rules. You can't look for something that's missing without first specifying the things that should be there.
Here's an option:
--Create and populate reference table "sites"
create table sites
([site] char (4))
INSERT INTO sites VALUES ('East')
INSERT INTO sites VALUES ('West')
-- Query against reference table
SELECT
ISNULL(table1.site, 'STE'),
instrument,
field
FROM (SELECT 'West' [Site], 0 [instrument], 0 [field]) table1
RIGHT JOIN sites on table1.[Site] = sites.[Site]
--or
-- Query against reference table
SELECT
ISNULL(table1.site, 'STE'),
instrument,
field
FROM sites
LEFT JOIN (SELECT 'West' [Site], 0 [instrument], 0 [field]) table1 on table1.[Site] = sites.[Site]
Let me know if you have questions on how this works.

Single query for several selects -even if one select returns empty

I need to make several select statements to get simple data (only one row containing one or several fields for each select).
Simplified example:
select name, price from article where id=125
select log, email from user where uid=241
I want to process only one single statement from php side (or: I do NOT want to prepare several statements, execute several statements, catch and handle exceptions for each execution and finally fetch result for each statement...).
I tried:
select * from (
(select name, price from article where id=125) as a,
(select log, email from user where uid=241) as b
)
which works great if every subselect returns values:
name | price | log | email
------------------------------------------
dummy | 12,04 | john | john#example.com
But if one of the subselects returns empty, the whole select returns empty.
What I want is: null values for empty resulting subselects.
I tried many things with ifnull() and coalesce(), but couldn't get the awaited result (I know how to use them with null values, but I didn't find a way to deal with them in the case of an empty result set).
I finally found a solution with left joins:
select * from (
(select 1) as thisWillNeverReturnEmpty
left join (select name, price from article where id=125) as a on 1
left join (select log, email from user where uid=241) as b on 1
)
which works perfectly even if one of the subqueries returns empty (or even both, therefore the "select 1").
Another way I found on SO would be to add a count(*) in each subquery to make sure there's a value.
But it all looks quite dirty and I can't believe there's no simple way just using something like ifnull().
What is the right way to do it?
The best way I finally found was:
select * from (
(select count(*) as nbArt, name, price from article where id=125) as a,
(select count(*) as nbUser, log, email from user where uid=241) as b
)
This way, no subquery ever returns empty, which solves the problem (there's always at least a "zero" count followed by null values).
Sample result when no article is found:
nbArt | name | price | nbUser | log | email
----------------------------------------------------------------
0 | null | null | 1 | john | john#example.com

Mysql-Select all tables from a database

I've a database called test and i've tables called x,y,z.
How do i select x,y,z and there is a column called date IN X,Y,Z check whether there is a particular date.
Is there any build in function that does this?
update
SELECT column date from all tables which is in a database called test
Thanks in advance!!
As far as I know, in SQL you cannot 'select a table', you can select some
column(s) from one or many tables at once. The result of such a query is an another table (temporary table) that you retrieve the data from.
Please be more specific about what exactly you want to do (e.g.: "I want to select a column 'z' from table 'tableA' and column 'y' from table 'tableB'") - then I'm sure your question has a pretty simple answer :)
SELECT x.date AS x_date, y.date AS y_date, z.date AS z_date FROM x,y,z;
That produces a result:
+---------+---------+---------+
| x_date | y_date | z_date |
+---------+---------+---------+
| | | |
| | | |
+---------+---------+---------+
Alternatively you can get everything in one column by ussuing a query:
SELECT date FROM x
UNION ALL
SELECT date FROM y
UNION ALL
SELECT date FROM z;
That produces a result:
+-------+
| date |
+-------+
| |
| |
+-------+
In the example above you would get also duplicate values in the single column. If you want to avoid duplicates replace 'UNION ALL' with 'UNION'
I'm still not sure if I undestood what you really want ot achieve, but I still hope that helps
Also take a look at:
http://www.w3schools.com/sql/sql_union.asp
http://www.sql-tutorial.net/SQL-JOIN.asp