#sql #sql-server #sql-server-2005 #tsql
#sql #sql-сервер #sql-server-2005 #tsql
Вопрос:
Что-то не так в моем запросе, когда я выполняю вычитание. Я использую MS SQL.
SELECT PT.PcbId
FROM dbo.DeviceTrace DT
JOIN dbo.PcbTrace PT ON DT.CompId = '101125937'
AND DT.DeviceID = PT.DeviceID
NOT IN (SELECT PB.PcbId
FROM dbo.DeviceTrace DT
JOIN dbo.PcbTrace PT ON DT.CompId = '101125937'
AND DT.DeviceID = PT.DeviceID
JOIN dbo.PanelBlockTrace PB ON PB.PcbID = PT.PcbID)
Не могли бы вы, пожалуйста, поправить меня?
Комментарии:
1. В чем проблема, с которой вы столкнулись?
Ответ №1:
Я переписал ваш запрос как:
SELECT PT.PcbId
FROM dbo.PcbTrace PT
WHERE EXISTS (SELECT NULL
FROM dbo.DeviceTrace DT
WHERE DT.DeviceID = PT.DeviceID
AND DT.CompId = '101125937')
AND NOT EXISTS (SELECT NULL
FROM dbo.PANELBLOCKTRACE pbt
WHERE pbt.pcbid = PT.pcbid)
…потому что вы скопировали свое первое объединение в часть NOT IN, но нет никакой связи между PANELBLOCKTRACE и DEVICETRACE на основе предоставленной вами информации.
Комментарии:
1. предложения exists плохо влияют на производительность, потому что они обходят всю таблицу, пока не найдут соответствующее значение. значение not exists намного хуже, поскольку оно должно пройти всю таблицу, чтобы подтвердить, что значение не существует. Внутреннее соединение или левое соединение (с проверкой null ) работает для лучшего использования индексов..
2. @M.R.: Вы ошибаетесь — EXISTS завершается при первом совпадении, что делает его лучшим выбором, если можно ожидать дубликатов. СОЕДИНЕНИЕ ПО ЛЕВОМУ КРАЮ / РАВНО НУЛЮ более эффективно в MySQL только при работе с ненулевыми столбцами — см.: explainextended.com/2009/09/15 /… vs: explainextended.com/2009/09/18 /…
3. @OMG Ponies, что значит ВЫБРАТЬ NULL ?
4. @Night Walker: Предложение SELECT в
EXISTS
не вычисляется — вы можете заменитьEXISTS (SELECT NULL
наEXISTS (SELECT 1/0
, что должно привести к ошибке деления на ноль. Вы обнаружите, что этого не произойдет, и запрос будет работать должным образом.5. @OMG Ponies, еще один вопрос, вы не выполнили никаких соединений в своем синтаксисе, можете ли вы объяснить, откуда здесь берутся соединения
Ответ №2:
Из вашего запроса выглядит так, как будто вы хотите исключить те идентификаторы PcbID, которые PanelBlockTrace
соответствуют вашим критериям фильтра CompID.
Попробуйте это:
select PT.PcbId
from dbo.DeviceTrace DT
INNER Join dbo.PcbTrace PT on DT.CompId = '101125937'
and DT.DeviceID = PT.DeviceID
LEFT JOIN dbo.PanelBlockTrace PB ON PB.PcbID = PT.PcbID
WHERE PB.PcbID IS NULL
Я бы предпочел это решение выше, чем a WHERE PT.PcbId NOT IN
потому что для этого потребовалось бы одно обращение к таблицам, а не 2, которые потребовались бы для a NOT IN
.
Ответ №3:
протестируйте это:
select PT.PcbId
from dbo.DeviceTrace DT INNER Join dbo.PcbTrace PT
on DT.CompId = '101125937' and DT.DeviceID = PT.DeviceID
where PT.PcbId
not in
(select PB.PcbId
from dbo.DeviceTrace DT INNER Join dbo.PcbTrace PT
on DT.CompId = '101125937' and DT.DeviceID = PT.DeviceID
INNER Join dbo.PanelBlockTrace PB
on
PB.PcbID = PT.PcbID)
Ответ №4:
Вы должны указать имя поля, когда вы говорите «не в» — вот так:
select PT.PcbId
from dbo.DeviceTrace DT INNER Join dbo.PcbTrace PT
on DT.CompId = '101125937' and DT.DeviceID = PT.DeviceID
and [fieldName] not in
(select PB.PcbId
from dbo.DeviceTrace DT INNER Join dbo.PcbTrace PT
on DT.CompId = '101125937' and DT.DeviceID = PT.DeviceID
INNER Join dbo.PanelBlockTrace PB
on
PB.PcbID = PT.PcbID)
Или, если вы хотите, чтобы это было в отдельном предложении where, тогда вам нужно:
select PT.PcbId
from dbo.DeviceTrace DT INNER Join dbo.PcbTrace PT
on DT.CompId = '101125937' and DT.DeviceID = PT.DeviceID
where [fieldName] not in
(select PB.PcbId
from dbo.DeviceTrace DT INNER Join dbo.PcbTrace PT
on DT.CompId = '101125937' and DT.DeviceID = PT.DeviceID
INNER Join dbo.PanelBlockTrace PB
on
PB.PcbID = PT.PcbID)
Хотя, вам действительно следует использовать «левое соединение», а не «не включено», что будет намного быстрее..
Комментарии:
1. Соединения в части NOT IN являются посторонними. И СОЕДИНЕНИЕ ПО ЛЕВОМУ КРАЮ / РАВНО НУЛЮ не работает быстрее на SQL Server: explainextended.com/2009/09/15 /…
2. @OMG Ponies: Я оставил все как есть, не зная, для чего нужна логика… но да, принимая пример за чистую монету, вы правы 🙂
Ответ №5:
Используйте EXCEPT вместо NOT IN, как:
SELECT query1
EXCEPT
SELECT query2
Ответ №6:
Ваш запрос кажется прекрасным.
Если что-то не так, пожалуйста, будьте более конкретны.
Кроме того, приведенный ниже запрос эквивалентен вашему:
SELECT PT.PcbId
FROM dbo.DeviceTrace DT
JOIN dbo.PcbTrace PT ON DT.CompId = '101125937'
AND DT.DeviceID = PT.DeviceID
EXCEPT
SELECT PcbId
FROM dbo.PanelBlockTrace
Он имеет более простую структуру и может помочь вам легче определить проблему.