简体   繁体   中英

How to get the reverse result to a sql query

I am using the following sql query to get the name of a branch that has submitted a report.

SELECT DISTINCT branch.b_name AS branch from branch, report_activity2

where branch.branch_id=report_activity2.branch_id 

and week =16
and year =2022

What I would also like to do is get the names of branches that have not submitted a report for the same week and year. I have tried the following query:

SELECT branch.b_name FROM branch

WHERE branch_id not in

(SELECT DISTINCT branch.b_name AS branch from branch, report_activity2

where branch.branch_id=report_activity2.branch_id 

and week =16
and year =2022)

But the second query result lists all the branches and does not exclude the branch from the first query. I am not sure if I am doing this completely wrong or I have just missed something simple. Any help to nudge me in the right direction would be appreciated.

In the first one you don't really need distinct and also you shouldn't use the old style join anyway:

SELECT b_name AS branch from branch
where exists (select * from report_activity2
where branch.branch_id=report_activity2.branch_id
and report_activity2.week =16
and report_activity2.year =2022);

In the second one you should compare branch_id to branch_ or b_name to b_name (provided it is unique) but you were checking branch_id in (... b_bame ...). Anyway it also doesn't need a join:

SELECT b_name AS branch from branch
where NOT exists (select * from report_activity2
where branch.branch_id=report_activity2.branch_id
and report_activity2.week =16
and report_activity2.year =2022);

EDIT: Some more explanation. With EXISTS (...), per row of branch, we are checking if in report_activity2 there is a row where branch_id matches "current" branch.branch_id and week = 16 and year 2022. If a match is found then it acts as a true on filtering branch. The good part is, there might be 1 or 1000 matching rows, it wouldn't matter and unlike a join it would just stop finding the first match thus more performant than doing a join (in which case you also would need to have DISTINCT, if there were 1000 rows matching a particular branch.branch_id, you first get 1000 rows and then DISTINCT select 1 one them). Somewhat visual explanation:

Branch:

Branch_id, b_name
1, 'b1'
2, 'b2'

Report_Activity2:

Branch_Id, Week, Year, ...
1,  1, 2022
1, 16, 2022
1, 16, 2022
1, 16, 2022
2,  1, 2022

With join it looks like (3 matches for 1):

1, 'b1', 1, 16, 2022
1, 'b1', 1, 16, 2022
1, 'b1', 1, 16, 2022

and then you use DISTINCT on b_name to get 'b1'.

With exists:

On

  1, 'b1' 

a match is found thus it immediately returns a true on first

1, 16, 2022 

without checking other rows in report_activity2. Resulting set is already:

1, 'b1'

Thus you don't need a DISTINCT hack.

can you try this mysql command ?

SELECT DISTINCT branch.b_name AS branch from branch, report_activity2

where branch.branch_id != report_activity2.branch_id 

and week =16
and year =2022 ;

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