SQL-запрос ищет точное совпадение с использованием внутреннего соединения

У меня есть 2 таблицы в базе данных SQL Server 2005 со структурами, представленными как таковые:

CAR: CarID bigint, CarField bigint, CarFieldValue varchar (50);

TEMP: CarField bigint, CarFieldValue varchar (50);

Теперь таблица TEMP на самом деле представляет собой табличную переменную, содержащую данные, собранные с помощью средства поиска. Основываясь на данных, содержащихся в TEMP, я хочу отфильтровать и получить все DISTINCT CarID из таблицы CAR, точно соответствующие этим строкам в таблице TEMP. Простое внутреннее соединение работает хорошо, но я хочу вернуть только те CarID, которые точно соответствуют ВСЕМ строкам в TEMP. По сути, каждая строка в TEMP должна обозначать фильтр И, тогда как в текущем запросе внутреннего соединения они действуют больше как фильтры ИЛИ. Чем больше строк в TEMP, тем меньше строк, которые я ожидаю, будет отображаться в моем наборе результатов для CAR. Я надеюсь, что я понимаю это ... если нет, пожалуйста, дайте мне знать, и я постараюсь уточнить.

Любые идеи о том, как я могу заставить эту работу? Спасибо!


person Shalan    schedule 23.09.2009    source источник


Ответы (4)


Вы используете COUNT, GROUP BY и HAVING, чтобы найти автомобили, которые имеют ровно столько математических строк, сколько вы ожидаете:

   select CarID
   from CAR c  
   join TEMP t on c.CarField = t.CarField and c.CarFieldValue = t.CarFieldValue
   group by CarID
   having COUNT(*) = <the number you expect>;

Вы даже можете сделать <the number you expect> скалярным подзапросом, например select COUNT(*) from TEMP.

person Remus Rusanu    schedule 23.09.2009
comment
Привет, Ремус, и спасибо за ответ. Как и в случае с Дэвидом выше, я сожалею, что не дождался еще немного, прежде чем обновить эту страницу! - person Shalan; 24.09.2009
comment
На самом деле remus, ваш имеет смысл, поскольку вы хорошо его объяснили ... и с меньшим запросом! +1 - person Shalan; 24.09.2009

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

select distinct carid from car where carid not in
(
select
  carid
from
  car c
  left outer join temp t on
    c.carfield = t.carfield
    and c.carfieldvalue = t.carfieldvalue
where
  t.carfield is null
)
person Abtin Forouzandeh    schedule 23.09.2009
comment
привет abtin и спасибо! фактически все строки будут иметь значения во всех столбцах. CAR на самом деле является ассоциативной таблицей с двумя другими таблицами. - person Shalan; 24.09.2009
comment
Ах, я неправильно прочитал вопрос и не понял, что темп представляет собой критерии поиска. - person Abtin Forouzandeh; 24.09.2009

Хм ...

;WITH FilteredCars
AS
(
  SELECT C.CarId
  FROM Car C
  INNER JOIN Temp Criteria 
     ON C.CarField = Criteria.CarField 
    AND C.CarFieldValue = Critera.CarFieldValue
  GROUP BY C.CarId
  HAVING COUNT(*) = (SELECT COUNT(*) FROM Temp)
)
SELECT *
FROM FilteredCars F
INNER JOIN Car C ON F.CarId = C.CarId

Основная предпосылка заключается в том, что для ВСЕХ критериев, соответствующих ВНУТРЕННЕМУ СОЕДИНЕНИЮ с вашей временной таблицей, должно быть создано столько записей, сколько есть в этой таблице. Предложение HAVING в конце запроса FilteredCars должно сузить результаты до тех, которые соответствуют всем критериям.

person David Andres    schedule 23.09.2009
comment
Привет, Дэвид, и спасибо за ответ! Хотел бы я отметить все 3 как ответы, но, к сожалению, я первым увидел ответ Анстандера и сразу же попробовал его. Однако с точки зрения удобочитаемости ваш легче понять. - person Shalan; 24.09.2009
comment
@ Шалан: все хорошо. Я думаю, что все мы в любом случае пошли в одном направлении! - person David Andres; 24.09.2009

person    schedule
comment
ВОА! Я не ожидал ТАКОГО быстрого ответа! Спасибо всем за ваш вклад. Astander, когда я обновил эту страницу, ваш был единственным ответом, и он работает на 100%! СПАСИБО. Не могли бы вы объяснить это мне, чтобы я мог лучше это понять? Я вижу добавленные критерии столбца соединения (чего я не думал делать !!!) - person Shalan; 24.09.2009
comment
Я сделал то же, что и вы. Сделайте соединения, но посчитайте происшествия. Сравните эти случаи с фактическим количеством записей во временной таблице. COUNT (1) просто подсчитывает строки во временной таблице, вы могли бы использовать * или любое поле / значение. Просто избегайте поиска полей, используя 1 - person Adriaan Stander; 24.09.2009