Это правильный способ использовать EXISTS? - PullRequest
1 голос
/ 28 февраля 2012

Я готовил SQL для экзамена, который у меня был в четверг, и у меня есть сомнения, правильно ли я использую оператор EXISTS.

Итак, у меня есть БД с 2 таблицами

    Machines                Maintenance
    ============            ==============
PK  ID_Machine          PK  ID_Machine  FK
    Name                PK  ID_Task     FK
    Date_bought             Date

Итак, запрос, который они хотят, чтобы я написал, говорит «Показать все данные с самой старой машины, которая не получала никакого обслуживания в 2011 году»

То, как я это сделал, таково:

SELECT M.ID_MACHINE, M.NAME, M.DATE_BOUGHT
FROM MACHINES M
WHERE NOT EXISTS (SELECT MA.*
                  FROM MAINTENANCE MA
                  WHERE MA.ID_MACHINE = M.ID_MACHINE
                  AND YEAR(MA.DATE) = 2011)                  
AND EXISTS (SELECT MIN(M2.DATE_BOUGHT)
              FROM MACHINE M2
              WHERE M2.ID_MACHINE = M.ID_MACHINE)

Это правильный способ сделать этот запрос? имеет ли смысл использовать SELECT MIN () внутри оператора EXISTS?

Спасибо всем заранее!

Ответы [ 5 ]

2 голосов
/ 28 февраля 2012

Когда вы используете существует, он только проверяет, что часть данных возвращается для фильтров (объединений и где).Часто вы видите существующие запросы с выбором 1 из .... Это потому, что фактические возвращаемые значения не используются.

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

SELECT M.ID_MACHINE, M.NAME, M.DATE_BOUGHT
FROM MACHINES M
WHERE NOT EXISTS (SELECT 1
              FROM MAINTENANCE MA
              WHERE MA.ID_MACHINE = M.ID_MACHINE
              AND YEAR(MA.DATE) = 2011)                  
    AND M.ID_MACHINE = (SELECT TOP 1 M2.ID_MACHINE
          FROM MACHINE M2
          WHERE M2.ID_MACHINE = M.ID_MACHINE
          ORDER BY M2.DATE_BOUGHT)
1 голос
/ 28 февраля 2012

Ваше первое использование EXISTS кажется правильным, но второе, кажется, отключено.Вы хотите проверить, является ли машина самой старой, но вы проверяете, существует ли машина с тем же MACHINE_ID (использование MIN не влияет на результат функции EXISTS).

Я не администратор БД, но учтите, что в некоторых реализациях подзапросы могут быть дорогостоящими, а в других они могут быть оптимизированы при размещении в функции EXISTS.Поэтому код stringpoet следует учитывать, когда вам действительно нужен код для запуска ... хотя, как я уже говорил, вам нужно GROUP BY все остальные поля.

Также обратите внимание, что вам не следует использовать ключевое слово WHERE дважды, но присоедините свои условия с помощью AND / OR.

Вот мое исправление к вашему и коду строкового поэта:

SELECT M.ID_MACHINE, M.NAME, MIN(M.DATE_BOUGHT)
FROM MACHINES M
WHERE NOT EXISTS (SELECT MA.*
                  FROM MAINTENANCE MA
                  WHERE MA.ID_MACHINE = M.ID_MACHINE
                  AND YEAR(MA.DATE) = 2011)                  
GROUP BY M.ID_MACHINE, M.NAME
1 голос
/ 28 февраля 2012

Думайте о EXISTS и NOT EXISTS как о логических условиях, которые вы можете использовать в своих запросах where.Они используются для проверки, являются ли другие условия данных истинными или ложными по отношению к данным, на которые вы просматриваете.

SELECT M.ID_MACHINE, M.NAME, M.DATE_BOUGHT
FROM MACHINES M

-- DO NOT want a machine with a maintenance year of 2011
WHERE NOT EXISTS (SELECT 1
                  FROM MAINTENANCE MA
                  WHERE MA.ID_MACHINE = M.ID_MACHINE
                  AND YEAR(MA.DATE) = 2011)      

-- DO want there to be a matching ID in the Machine table            
WHERE EXISTS (SELECT 1
              FROM MACHINE M2
              WHERE M2.ID_MACHINE = M.ID_MACHINE)

Как уже упоминал Джастин, возвращаемые значения подзапросов не используются, поэтомуSELECT 1 - это соглашение для EXISTS/NOT EXISTS.

1 голос
/ 28 февраля 2012

Цитирование стандарта SQL-92 :

8,8

     Function

     Specify a test for a non-empty set.

     Format

     <exists predicate> ::= EXISTS <table subquery>


     Syntax Rules

        None.

     Access Rules


        None.

     General Rules

     1) Let T be the result of the <table subquery>.

     2) If the cardinality of T is greater than 0, then the result of
        the <exists predicate> is true; otherwise, the result of the
        <exists predicate> is false.

     Leveling Rules

     1) The following restrictions apply for Intermediate SQL:

          None.

     2) The following restrictions apply for Entry SQL in addition to
        any Intermediate SQL restrictions:

          None.

Итак, нет, в синтаксисе подзапроса нет специальных правил (только то, что он действителен). Оператор exists просто заботится о том, возвращает ли он какие-либо строки.

0 голосов
/ 28 февраля 2012

Я думаю, что это был бы лучший способ сделать это.

SELECT TOP 1 MIN(A.Date_bought), A.ID_Machine, A.Name
FROM Machines A
JOIN Maintenance B on A.ID_Machine = B.ID_Machine
WHERE DATEPART(year, B.Date) != '2011'
GROUP BY A.Date_bought, A.ID_Machine, A.Name
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...