как я могу поставить минус в этом запросе?

#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
  

Он имеет более простую структуру и может помочь вам легче определить проблему.