Помогите преобразовать подзапрос в запрос с объединениями - PullRequest
3 голосов
/ 13 марта 2010

Я застрял на запрос с объединением. На сайте клиента работает mysql4, поэтому подзапрос не вариант. Мои попытки переписать с помощью объединения не увенчались успехом.

Мне нужно выбрать всех подрядчиков, перечисленных в таблице подрядчиков, которых нет в таблице contractors2label, с указанным идентификатором ярлыка и идентификатором округа. Тем не менее, они могут быть перечислены в Contractors2label с другими идентификаторами лейблов и округов.

Таблица: подрядчики

cID (основной, автономный номер)
компания (варчар)
... и т.д ...

Таблица: подрядчики2label

ИДС
labelID
countyID
PSID

Этот запрос с подзапросом работает:

SELECT company, contractors.cID
   FROM contractors
   WHERE contractors.complete = 1
   AND contractors.archived = 0
   AND contractors.cID NOT IN (
     SELECT contractors2label.cID FROM contractors2label
        WHERE labelID <> 1 AND countyID <> 1
   )

Я думал, что этот запрос с объединением будет эквивалентен, но он не возвращает результатов. Ручное сканирование данных показывает, что я должен получить 34 строки, что и возвращает подзапрос, приведенный выше.

SELECT company, contractors.cID
   FROM contractors 
   LEFT OUTER JOIN contractors2label ON contractors.cID = contractors2label.cID
   WHERE contractors.complete = 1
   AND contractors.archived = 0
   AND contractors2label.labelID <> 1
   AND contractors2label.countyID <> 1
   AND contractors2label.cID IS NULL

Ответы [ 2 ]

2 голосов
/ 13 марта 2010

Когда вы ограничиваете предложение where, используя столбцы в таблице, к которой присоединено LEFT, вы фактически удаляете часть объединения LEFT OUTER, поскольку вы фильтруете столбцы, которые должны быть там. Попробуйте вместо этого:

SELECT company, contractors.cID
   FROM contractors 
   LEFT OUTER JOIN contractors2label 
       ON (contractors.cID = contractors2label.cID
           AND contractors2label.labelID <> 1
           AND contractors2label.countyID <> 1)
   WHERE contractors.complete = 1
   AND contractors.archived = 0
   AND contractors2label.cID IS NULL

Это ограничение действует как часть объединения, поэтому нулевые значения все еще могут использоваться в запросе большего размера.

2 голосов
/ 13 марта 2010

При выполнении LEFT JOIN необходимо поместить все условия JOIN в предложение ON.

В вашем примере вы получаете NULL для левосторонних столбцов, которые не существуют, но затем вы сравниваете их со значениями (<> 1), которые не работают.

SELECT c.company, c.cID
   FROM contractors c
   LEFT JOIN contractors2label c2
          ON ( c2.cID = c.cID AND c2.labelID <> 1 AND c2.countyID <> 1 )
   WHERE c.complete = 1
   AND c.archived = 0
   AND c2.cID IS NULL

Кстати: использование псевдонимов (например, c в моем примере) облегчает чтение и написание ваших запросов.

...