Select all records don't meet certain conditions in a joined table
SELECT *
FROM posts p
WHERE NOT EXISTS(
SELECT 1
FROM comments c
WHERE c.comment_date >= 'deadline'
AND p.post_id = c.post_id
)
How to select rows with no matching entry in another table?
Here's a simple query:
SELECT t1.ID
FROM Table1 t1
LEFT JOIN Table2 t2 ON t1.ID = t2.ID
WHERE t2.ID IS NULL
The key points are:
LEFT JOIN
is used; this will return ALL rows fromTable1
, regardless of whether or not there is a matching row inTable2
.The
WHERE t2.ID IS NULL
clause; this will restrict the results returned to only those rows where the ID returned fromTable2
is null - in other words there is NO record inTable2
for that particular ID fromTable1
.Table2.ID
will be returned as NULL for all records fromTable1
where the ID is not matched inTable2
.
How to select all records from one table that do not exist in another table?
SELECT t1.name
FROM table1 t1
LEFT JOIN table2 t2 ON t2.name = t1.name
WHERE t2.name IS NULL
Q: What is happening here?
A: Conceptually, we select all rows from table1
and for each row we attempt to find a row in table2
with the same value for the name
column. If there is no such row, we just leave the table2
portion of our result empty for that row. Then we constrain our selection by picking only those rows in the result where the matching row does not exist. Finally, We ignore all fields from our result except for the name
column (the one we are sure that exists, from table1
).
While it may not be the most performant method possible in all cases, it should work in basically every database engine ever that attempts to implement ANSI 92 SQL
How can I join two tables, keeping rows that do not meet the JOIN condition?
you should be using LEFT JOIN
SELECT a.staff, COUNT(b.assign) as count
FROM staffinfo a
LEFT JOIN ticket b
ON b.assign = a.staff
GROUP BY a.staff
- SQLFiddle Demo
To fully gain knowledge about joins, kindly visit the link below:
- Visual Representation of SQL Joins
How do I find records that are not joined?
select * from a where id not in (select a_id from b)
Or like some other people on this thread says:
select a.* from a
left outer join b on a.id = b.a_id
where b.a_id is null
SQL: Select records where ALL joined records satisfy some condition
Assuming no need for correlation, use:
SELECT a.*
FROM A a
WHERE EXISTS(SELECT NULL
FROM B b
HAVING MIN(b.some_val) > a.val)
If you do need correlation:
SELECT a.*
FROM A a
WHERE EXISTS(SELECT NULL
FROM B b
WHERE b.id = a.id
HAVING MIN(b.some_val) > a.val)
Explanation
The EXISTS
evaluates on a boolean, based on the first match - this makes it faster than say using IN, and -- unlike using a JOIN -- will not duplicate rows. The SELECT portion doesn't matter - you can change it to EXISTS SELECT 1/0 ...
and the query will still work though there's an obvious division by zero error.
The subquery within the EXISTS
uses the aggregate function MIN to get the smallest B.some_val - if that value is larger than the a.val value, the a.val is smaller than all of the b values. The only need for a WHERE
clause is for correlation - aggregate functions can only be used in the HAVING
clause.
Obtain all the records in table A, if they meet the conditions with table B
There are some problems in your query/logic:
select max(id), name, ... group by uid
will not give you the row with the maximum id. It will give you the maximum id, and the values of any row that is in that group. If there is only one row per group (e.g. if uid is unique/the primary key), that might be the one you are looking for, otherwise it is not determined (and will fail for MySQL 5.7), see MySQL Handling of GROUP BY and any question on stackoverflow about an errormessage withsql_mode=only_full_group_by
.left join ... ON bonus_id = id where rb1.player_id IS NULL
will be false if there is any player that has redeemed this bonusid. If you included the playerid in theon
-condition, it would be true if the player would not have redeemed all different ids for a givenuid
(which is probably impossible).something similar happens since you
join
viarb1.bonus_id = br1.id
and apply your condition to thisid
(but notuid
): if there is some old entry with a biggerredeem_count
, it evaluates to true even if there is a latest id with a lowerredeem_count
(that won't be part of thegroup by
, since you filtered it out).instead, you probably would need to apply your filter after
left join
, e.g usinggroup by ... having ...
orselect ... from (select ... group by ...) where ...
With this said, I won't fix your query (although it may be salvageable), but write you a new one with a new structure.
Breaking it into steps, first, get a list of all active bonuses:
select * from bonus_records br
where not exists
(select 1 from bonus_records br1
where br1.uid = br.uid and br1.id > br.id);
Next step is to check how often a specific uid has been redeemed by a specific player (the uid
-information is obtained by checking the bonus_records
-table):
select br.uid, count(*)
from redeemed_bonuses rb
join bonus_records br on br.id = rb.bonus_id
where rb.player_id = 1
and not (rb.completed = 0 and rb.canceled = 0)
group by br.uid;
The condition not (rb.completed = 0 and rb.canceled = 0)
is adepted to fit the requirements according to the comments.
Now join those two and apply your conditions about the actual count being lower than redeem_count
:
select pb.*, rd.actual_count from
(select * from bonus_records br
where not exists
(select 1 from bonus_records br1
where br1.uid = br.uid and br1.id > br.id)
) pb -- active potential bonuses
left join
(select br.uid, count(*) as actual_count
from redeemed_bonuses rb
join bonus_records br on br.id = rb.bonus_id
where rb.player_id = 1
and not (rb.completed = 0 and rb.canceled = 0)
group by br.uid
) rd -- redeemed bonuses by that user
on pb.uid = rd.uid
where rd.actual_count is null -- uid never redeemed (left join empty)
or rd.actual_count < pb.redeem_count -- still some remaining
or pb.redeem_count = 0 -- unlimited bonus
Selecting all rows from one table where condition in joined table
Try this
SELECT
pro.productname,
pr.productionreportid,
IFNULL(pr.qty, 0) qty
FROM
Products pro
LEFT JOIN ProductionReport pr
ON pro.productid = pr.productid
AND DATE(pr.date) = '2013-04-08'
Basically move the date condition from WHERE clause to the JOIN clause
Find records from one table which don't exist in another
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 '*
')
Related Topics
Postgresql - View Schema Privileges
Differencebetween Postgres Distinct VS Distinct On
Kafka Connect Jdbc VS Debezium Cdc
Copy from One Database to Another Using Oracle SQL Developer - Connection Failed
How to Get a View Table Query (Code) in SQL Server 2008 Management Studio
Besides a Declarative Language, Is SQL a Functional Language
SQL Queries on String Columns - Sorting According to Language
Multiple Left Joins on Multiple Tables in One Query
How to Do SQL Select Top N ... in As400
Inserting Data into a Temporary Table
SQL Server 2008 Unique Column That Is Case Sensitive
MySQL "Create Table If Not Exists" -> Error 1050
Correct Way to Select from Two Tables in SQL Server with No Common Field to Join On
How to Avoid "Table Mutating" Errors
How to Use a Case Statement in a SQL from Clause