2012-02-28 4 views
1

Я делаю некоторый SQL для экзамена, который у меня есть в четверг, и у меня есть сомнения, если я правильно использую инструкцию EXISTS.Правильно ли это использовать 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?

Заранее благодарен всем!

+0

Ну .... то, что происходит, когда вы пытаетесь выполнить запрос? –

+0

Ну, дело в том, что у меня на самом деле нет этой БД, созданной в любой СУБД. Это всего лишь упражнение в учебнике, и я решаю его в листе бумаги. К сожалению, у учебника нет ответов, поэтому я и спрашивал :) – nachoargentina

+0

ну для начала, вам нужно 'AND' * вместо * второго' WHERE'. Кроме того, никогда не используйте 'SELECT MIN()' внутри 'EXISTS' - это не имеет смысла. – Bohemian

ответ

2

При использовании существует только проверка того, что часть данных возвращается фильтрам (объединениям и где). Часто вы увидите существующие запросы с выбором 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) 
+0

Правильно, поэтому в моем случае с условием EXISTS я пытаюсь выбрать самую старую машину ... вот почему я включил MIN() в оператор select SubQuery. Я подумал, что, выполняя это, оператор EXISTS устранит все другие машины, но тот, у которого есть MIN (Date_bought). Это так? или я решаю это неправильно? – nachoargentina

+0

Обновление моего ответа, но короткий ответ заключается в том, что вы действительно решаете это неправильно. Это была новая идея, хотя :) –

+0

Простите, проигнорируйте мой последний комментарий, я не прочитал весь ваш комментарий до конца, только первый абзац. Итак, вы думаете, что это может сработать так? Я так и думал, поскольку, как вы сказали, MIN() теоретически будет действовать как фильтр. Я попытаюсь проверить это в реальной базе данных, как только у меня появится шанс. – nachoargentina

0

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

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 
+0

-1: ОП спрашивает, действительно ли его/ее запрос действителен, а не переписывать его. –

+1

Я думаю, что это не сработает, так как 'MIN' является агрегатом, и у вас нет' GROUP BY' – Yuval

+0

Спасибо, пропустил GROUP BY :) Кроме того, к Джеку он также спросил, правильно ли это делается, что я Думаю, что так, поэтому я предложил другое решение. Не нужно понижать голос, когда у меня только 8 человек. Jeez. lol – stringpoet

1

Цитируя SQL-92 standard:

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

Итак, в этом случае оператор EXISTS вернет true для одной конкретной строки в таблице M2. Поскольку эта таблица имеет внешнюю ссылку на основную таблицу в моем запросе, означает ли это, что при этом она будет исключать все строки в моей основной таблице, кроме той, которая имеет значение MIN (Date_bought)? Потому что это в основном то, что я нацелился на – nachoargentina

+0

Нет, он не удалит строки из любой таблицы. Это не оператор 'delete' и' truncate'. –

1

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

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) 

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

+0

Но, поскольку я только что редактировал свой пост, MIN вроде действует как фильтр сам по себе ... так что я задаюсь вопросом, будет ли работать MIN или нет .... I никогда не пробовал, и теоретически он мог бы работать. Я обновил свой ответ, чтобы задать вопрос. Я могу загрузить некоторые фиктивные данные, чтобы увидеть :) –

+0

Протестировано, и это терпит неудачу. Я обновляю свой ответ :) –

+0

@JustinPihony Хорошо, tx для тестирования этого для меня! хорошо знать, что это было не так. Я его притягиваю. – nachoargentina

1

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

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

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

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

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 
+0

Хорошо, отлично, что делало вещи намного яснее! tx Yuval, я буду использовать ваш код вместо тех, которые с EXIST для моего ответа – nachoargentina

Смежные вопросы