2016-12-07 5 views
2

У меня есть две таблицы Card и History с отношением «один ко многим»: одна карта может иметь одну или несколько историй. Card имеет столбец CardId, а History имеет CardId и столбец StatusId.SQL Server NOT EXISTS эффективность

Мне нужен скрипт SQL, который выбирает единственные карты, у которых нет истории с StatusId = 310.

Это то, что я пробовал.

SELECT 
    C.CardId 
FROM 
    Card C 
WHERE NOT EXISTS (SELECT * 
        FROM History H 
        WHERE H.CardId = C.CardId AND H.StatusId = 310) 

Но я хочу знать, есть ли эффективный способ.

Заранее спасибо.

+1

Почему вы хотите использовать 'GROUP BY' для этого? 'WHERE NOT EXISTS' будет наиболее логичным для использования. – Siyual

+0

Все, что мне нужно, это знать, есть ли более эффективный способ. –

+1

Я бы написал это же (я прочитал необоснованные утверждения о том, что 'select null' в' where [not] exists' немного более результативен). Если этот запрос не работает, как вы хотели бы, посмотрите на план выполнения. – HoneyBadger

ответ

4

Чтобы ответить на ваш вопрос о том, есть ли более эффективный способ:

Короткий ответ: Нет, not exists, скорее всего, является наиболее эффективным методом.

Длинный ответ: статья Аарона Бертранда с эталонами для разных способов делать то же самое Should I use not in, outer apply, left outer join, except, or not exists? Спойлер: not exists побед.

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

select c.CardId 
    from Card c 
    where not exists(
    select 1 
     from History h 
     where h.CardId=c.CardId 
     and h.StatusId=310 
      ) 
+0

Спасибо за ваш ответ. –

+0

Рад помочь! Спасибо @AaronBertrand за все тяжелую работу над этой статьей. – SqlZim

1

Ваш метод NOT EXISTS выглядит разумным, но есть и другой подход.

SELECT * 
FROM Card C 
WHERE EXISTS (SELECT 1 
       FROM history H 
       WHERE H.CardId = C.CardId 
       HAVING Count(CASE WHEN H.StatusId = 310 THEN 1 END) = 0) 

Проверьте производительность при запуске обоих запросов с данными в реальном масштабе времени

+0

Кажется, что 'NOT EXISTS' быстрее. '1600' против' 2100' milliseconds.Thanks для вашего подхода. –

3

Что вы после этого называется «отрицательным JOIN». Вот версия без подзапроса:

SELECT c.CardId 
FROM Card c 
LEFT OUTER JOIN History h 
    ON h.CardId = c.CardId 
    AND h.StatusId = 310 
WHERE h.CardId IS NULL;