У меня есть три таблицы: клиенты, счета и состояния счетов. Я хотел бы всегда получать клиента, и если у него есть счета, то только счета, которые можно изменить. Я пробую что-то вроде этого:
select * from Clients
left join Bills on Bills.IDClient = Clients.IDClient
left join BillsStates on BillsStates.IDBillState = Bills.IDState
and BillsStates.AllowModify = 1
Проблема в том, что я получаю все счета клиента, независимо от того, можно их изменить или нет.
Я попытался выполнить правильное соединение, но в этом случае не получил никакого результата.
Возможно ли это с объединениями или мне нужен подзапрос? Я бы предпочел решение с объединениями, но если нет возможности сделать это таким образом, я бы принял другое решение.
Узнайте, какое левое соединение при возврате: внутреннее соединение по строкам плюс несопоставленные левые строки таблицы, расширенные нулями. Всегда знайте, какое внутреннее соединение вам нужно как часть левого соединения. A, где это требует, чтобы правый столбец таблицы не был нулевым после левого соединения, которое у вас есть, удаляет все строки, расширенные нулями, т.е. оставляет только внутреннее соединение в строках, т.е. «превращает внешнее соединение во внутреннее соединение».
Это часто задаваемые вопросы. Пожалуйста, всегда гуглите много четких, кратких и конкретных версий / формулировок вашего вопроса / проблемы / цели с и без ваших конкретных строк / имен и читайте много ответов. Добавьте в поисковые запросы релевантные ключевые слова, которые вы обнаружите. Если вы не нашли ответа, отправьте сообщение, используя поиск по одному из вариантов по заголовку и ключевым словам для тегов. См. Текст при наведении курсора мыши на стрелку "против". Пожалуйста, прочтите и действуйте в соответствии с текстом, указанным при наведении курсора мыши на стрелку вниз, и введите в Google запрос «домашнее задание stackexchange».
Возможный дубликат Левое соединение не возвращает все строки
используйте внутреннее соединение между счетами и 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: да, но это более читабельно (кто-то ранее задавал вопрос, похожий на то, что JOIN JOIN ON ON, и все были в замешательстве).
вы можете попробовать это.
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
Добавьте образцы данных таблицы и ожидаемый результат - все в виде форматированного текста, а не изображений. (Также посмотрите stackoverflow.com/help/mcve.)