Reputation: 19356
I have three tables, Clients, Bills and BillsStates. I would like to get always the client and if it has bills, only the bills that can be modified. I am trying something like that:
select * from Clients
left join Bills on Bills.IDClient = Clients.IDClient
left join BillsStates on BillsStates.IDBillState = Bills.IDState
and BillsStates.AllowModify = 1
The problem with that is that I get all the bills of the client, no matter if they can be modified or not.
I have tried to with a right join, but in this case I have not get any result.
Is it possible with joins or perhaps I need some subquery? I would prefer a solution with joins, but if there is no way to do it in this way, I would accept another solution.
Upvotes: 0
Views: 74
Reputation: 62576
Rather than joining on a subquery, you can also re-arrange the order of joins
SELECT c.*, b.*, bs.* -- Todo: only the relevant columns
FROM Bills b
JOIN BillsStates bs ON BillsStates.IDBillState = Bills.IDState
RIGHT JOIN Clients c ON b.IDClient = c.IDClient
Upvotes: 0
Reputation: 272006
Your query simply replaces BillsStates.*
with null values where BillsStates.AllowModify = 1
condition fails:
| IDClient | Name | IDClient | IDState | Name | IDBillState | AllowModify |
|----------|------|----------|---------|--------|-------------|-------------|
| 1 | John | 1 | 1 | Bill 1 | NULL | NULL |
| 1 | John | 1 | 2 | Bill 2 | 2 | 1 |
| 2 | Jane | NULL | NULL | NULL | NULL | NULL |
Rearrange the join type and condition to get the desired result:
SELECT *
FROM Clients
LEFT JOIN (Bills
INNER JOIN BillsStates ON BillsStates.IDBillState = Bills.IDState) ON Bills.IDClient = Clients.IDClient AND BillsStates.AllowModify = 1;
| IDClient | Name | IDClient | IDState | Name | IDBillState | AllowModify |
|----------|------|----------|---------|--------|-------------|-------------|
| 1 | John | 1 | 2 | Bill 2 | 2 | 1 |
| 2 | Jane | NULL | NULL | NULL | NULL | NULL |
Upvotes: 1
Reputation: 32003
use inner join between bills and BillsStates instead left join and do left join with client
select c.* from Clients c
left join Bills b on b.IDClient = c.IDClient
inner join BillsStates bs
on bs.IDBillState = b.IDState and b.AllowModify = 1
Upvotes: 0
Reputation: 13393
you can try this.
select * from Clients
left join
( select * from Bills
inner join BillsStates on BillsStates.IDBillState = Bills.IDState
and BillsStates.AllowModify = 1
) B ON B.IDClient = Clients.IDClient
Upvotes: 1
Reputation:
select * from Clients
left join Bills
inner join BillsStates on BillsStates.IDBillState = Bills.IDState
on Bills.IDClient = Clients.IDClient
and BillsStates.AllowModify = 1
The problem you have is that you only cause the BillsStates
record to be excluded, because your filter is only in its join condition. Instead, you can re-order and move it into Bills
's join condition.
Upvotes: 3