Можно ли фильтровать в левом соединении?

У меня есть три таблицы: клиенты, счета и состояния счетов. Я хотел бы всегда получать клиента, и если у него есть счета, то только счета, которые можно изменить. Я пробую что-то вроде этого:

select * from Clients
left join Bills on Bills.IDClient = Clients.IDClient
left join BillsStates on BillsStates.IDBillState = Bills.IDState
and BillsStates.AllowModify = 1

Проблема в том, что я получаю все счета клиента, независимо от того, можно их изменить или нет.

Я попытался выполнить правильное соединение, но в этом случае не получил никакого результата.

Возможно ли это с объединениями или мне нужен подзапрос? Я бы предпочел решение с объединениями, но если нет возможности сделать это таким образом, я бы принял другое решение.

Добавьте образцы данных таблицы и ожидаемый результат - все в виде форматированного текста, а не изображений. (Также посмотрите stackoverflow.com/help/mcve.)

jarlh 13.09.2018 13:51

Узнайте, какое левое соединение при возврате: внутреннее соединение по строкам плюс несопоставленные левые строки таблицы, расширенные нулями. Всегда знайте, какое внутреннее соединение вам нужно как часть левого соединения. A, где это требует, чтобы правый столбец таблицы не был нулевым после левого соединения, которое у вас есть, удаляет все строки, расширенные нулями, т.е. оставляет только внутреннее соединение в строках, т.е. «превращает внешнее соединение во внутреннее соединение».

philipxy 13.09.2018 18:49

Это часто задаваемые вопросы. Пожалуйста, всегда гуглите много четких, кратких и конкретных версий / формулировок вашего вопроса / проблемы / цели с и без ваших конкретных строк / имен и читайте много ответов. Добавьте в поисковые запросы релевантные ключевые слова, которые вы обнаружите. Если вы не нашли ответа, отправьте сообщение, используя поиск по одному из вариантов по заголовку и ключевым словам для тегов. См. Текст при наведении курсора мыши на стрелку "против". Пожалуйста, прочтите и действуйте в соответствии с текстом, указанным при наведении курсора мыши на стрелку вниз, и введите в Google запрос «домашнее задание stackexchange».

philipxy 13.09.2018 18:51

Возможный дубликат Левое соединение не возвращает все строки

philipxy 13.09.2018 18:51
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
4
70
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

используйте внутреннее соединение между счетами и BillsStates, а не левое соединение и сделайте левое соединение с клиентом

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
select * from Clients
left join Bills
    inner join BillsStates on BillsStates.IDBillState = Bills.IDState
on Bills.IDClient = Clients.IDClient
and BillsStates.AllowModify = 1

Проблема в том, что вы вызываете исключение только записи BillsStates, потому что ваш фильтр находится только в состоянии соединения. Вместо этого вы можете изменить порядок и переместить его в условие соединения Bills.

Ответ принят как подходящий

Ваш запрос просто заменяет BillsStates.* нулевыми значениями, когда условие BillsStates.AllowModify = 1 не выполняется:

| 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        |

Измените тип и условие соединения, чтобы получить желаемый результат:

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        |

Скобки необязательны. Фактически, JOIN и ON играют роль, аналогичную скобкам. Чтобы определить, к какому JOIN относится конкретное предложение ON, вы работаете в обратном направлении, пока не найдете JOIN, с которым еще не было связано предложение ON (точно так же вы находите, какой ( соответствует ), работая в обратном направлении, пока не найдете непревзойденный)

Damien_The_Unbeliever 13.09.2018 14:04

@Damien_The_Unbeliever: да, но это более читабельно (кто-то ранее задавал вопрос, похожий на то, что JOIN JOIN ON ON, и все были в замешательстве).

Salman A 13.09.2018 14:07

вы можете попробовать это.

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

Вместо того, чтобы присоединяться к подзапросу, вы также можете изменить порядок соединений

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

Другие вопросы по теме