MySQL “NOT IN” query 3 tables
Avoid NOT IN
like the plague if
SELECT ID_Courses FROM Evaluation where `NAME`='JOHN' and Year=1
could ever contain NULL. Instead, use NOT EXISTS or Left Joins
use explicit joins, not 1980's style joins using the WHERE
clause
To illustrate the misery of NOT IN:
SQL NOT IN () danger
create table mStatus
( id int auto_increment primary key,
status varchar(10) not null
);
insert mStatus (status) values ('single'),('married'),('divorced'),('widow');
create table people
( id int auto_increment primary key,
fullName varchar(100) not null,
status varchar(10) null
);
Chunk1:
truncate table people;
insert people (fullName,`status`) values ('John Henry','single');
select * from mstatus where `status` not in (select status from people);
** 3 rows, as expected **
Chunk2:
truncate table people;
insert people (fullName,`status`) values ('John Henry','single'),('Kim Billings',null);
select * from mstatus where status not in (select status from people);
no rows, huh?
Obviously this is 'incorrect'. It arises from SQL's use of three-valued logic,
driven by the existence of NULL, a non-value indicating missing (or UNKNOWN) information.
With NOT IN, Chunk2 it is translated like this:
status NOT IN ('married', 'divorced', 'widowed', NULL)
This is equivalent to:
NOT(status='single' OR status='married' OR status='widowed' OR status=NULL)
The expression "status=NULL" evaluates to UNKNOWN and, according to the rules of three-valued logic,
NOT UNKNOWN also evaluates to UNKNOWN. As a result, all rows are filtered out and the query returns an empty set.
Possible solutions include:
select s.status
from mstatus s
left join people p
on p.status=s.status
where p.status is null
or use not exists
SQL query NOT IN from 3 tables with conditions
I managed to work it with another parameter.
SELECT * FROM (SELECT `email`, `secretId` FROM `old_data`
WHERE `type` = 'Accounts' AND `email` NOT IN (SELECT `email1` FROM `clients`)) AS t1
WHERE t1.secretId NOT IN (SELECT `secretId` FROM `trashes` WHERE `type` = 'Accounts')
Also works with
SELECT od.`email`, od.`secretId`
FROM `old_data` od
WHERE od.`type` = 'Accounts' AND
od.`email` NOT IN (SELECT `email1` FROM `clients`) AND
od.`secretId` NOT IN (SELECT `secretId` FROM `trashes` WHERE `type` = 'Accounts');
Thanks for helping. :)
SQL 'Not in' query involving three tables
Assumption: A product can be part of categories that exist, categories that do not exist, or no categories at all. You have not asked for products that belong to no categories at all, so the first LEFT JOIN from product to procduct_to_category should be an INNER JOIN.
Caveat: I am rusty at mysql so I am using SQL SERVER syntax. I forget if mysql has ON clauses or uses where clauses for JOINs. If ON clause is not supported, change them into WHERE clauses.
There are two common approaches: OUTER JOIN or a NOT IN clause (or a NOT EXISTS clause, which often behaves the same performance-wise as the NOT IN clause.)
OUTER JOIN
select p.*, p2c.category_id
from product p
INNER JOIN product_to_category p2c ON (p.product_id = p2c.product_id)
LEFT JOIN category c ON p2c.category_id = c.category_id
WHERE c.category_id IS NULL
The test for null will find the unmatched records.
NOT IN clause
SELECT p.*, p2c.category_id
FROM product p
INNER JOIN product_to_category p2c ON (p.product_id = p2c.product_id)
WHERE p2c.category_id NOT IN (SELECT c.category_id FROM category c)
SQL join 3 tables when no matching records exist on 2 tables
Place the where
clause after all join like below
If you want to select domains
which does not exist in either of the two table keywords
and comments
, then use OR
condition in WHERE
clause
SELECT * FROM domains
LEFT JOIN keywords ON domains.domain_id=keywords.domain_id
LEFT JOIN comments ON domains.domain_id=comments.domain_id
WHERE keywords.domain_id IS NULL
OR comments.domain_id IS NULL
If you want to select the domains
which does not exist in both the tables keywords
and comments
, just replace the OR
condition in WHERE
clause to AND
like below
SELECT * FROM domains
LEFT JOIN keywords ON domains.domain_id=keywords.domain_id
LEFT JOIN comments ON domains.domain_id=comments.domain_id
WHERE keywords.domain_id IS NULL
AND comments.domain_id IS NULL
MySQL how to join 3 tables when one doesn't have a common key
You can "chain" your joins:
SELECT title, author_last, on_hand
FROM book b
JOIN inventory i ON b.book_code = i.book_code
JOIN wrote w ON b.book_code = w.book_code
JOIN author a ON a.author_num = w.author_num
WHERE branch_num = 4
How to select multiple tables in single query mysql? (some tables have no data yet)
All the tables equally have id, first_name, last_name, gender and only deliveries table has their own data. (the other 2 tables are currently empty.)
Now, I want to select all of them in 1 query
I suspect that you are looking for union all
:
SELECT first_name, last_name, gender FROM patients
UNION ALL
SELECT first_name, last_name, gender FROM customers
UNION ALL
SELECT first_name, last_name, gender FROM deliveries
This will combine all records available in the 3 tables in the resultset. On the other hand, using an (implicit) cross join
like you do would generate a cartesian product of the 3 tables, with 9 columns (3 * 3) in the resultset (that is, if you fix the ambiguity on column names that you currently have).
If you want to eliminate duplicates accross tables, you can use union
instead of union all
.
If you want to limit the number of records in the resultset, you can do this as follows:
(
SELECT first_name, last_name, gender FROM patients
UNION ALL
SELECT first_name, last_name, gender FROM customers
UNION ALL
SELECT first_name, last_name, gender FROM deliveries
)
ORDER BY id
LIMIT 5000
Note that, functionaly this does require an order by
clause, otherwise the ordering of the results is undefined (I assumed id
).
Join three tables on condition
We can do LEFT JOIN
on B
and C
tables separately using id
. Now, we can utilize COALESCE()
, to consider B.bedrooms
first (if not null), else C.bedrooms
. Now, there is a chance that both can be null (that is, id
does not exist in either of the tables).
In that case, if you don't want those rows, you can put an additional WHERE
condition to consider only those id(s), which has atleast one matching row in either B
or C
.
Here is one way:
select A.id,
A.price,
COALESCE(B.bedrooms, C.bedrooms) AS bedrooms
from A
left join B on A.id = B.id
left join C on A.id = C.id
WHERE NOT (B.bedrooms IS NULL AND
C.bedrooms IS NULL)
order by A.id
Related Topics
PHP Configuration: It Is Not Safe to Rely on the System's Timezone Settings
How to Replace (Monkeypatch) PHP Functions
Composer Installing: the JSON Extension Is Missing
Find Common Values in Multiple Arrays with PHP
Using Strtotime for Dates Before 1970
PHP Session Side-Effect Warning with Global Variables as a Source of Data
Naming Convention Issues When Using Codeigniter in Windows and Linux
Why We Need Curlopt_Ssl_Verifypeer in Windows
How to Check If There Is a There Is a Wget Instance Running
Trying to Access Array Offset on Value of Type Bool in PHP 7.4
PHP Remove Special Character from String
Execute Commands on Remote MAChine via PHP
How to Chain Method on a Newly Created Object
Best Way to Create an Empty Object in JSON with PHP