Як можна видалити SQL, використовуючи підзапит


15

Наступний код додав один з наших розробників для видалення дублікатів записів із таблиці:

DELETE  SubQuery

FROM
(
    SELECT  ID
            ,FK1
            ,FK2
            ,CreatedDateTime
            ,ROW_NUMBER() OVER(PARTITION BY FK1, FK2 ORDER BY CreatedDateTime) AS RowNumber

    FROM    Table
)
AS SubQuery

WHERE   RowNumber > 1

Переглядаючи код, я припускав, що він не працюватиме, проте тестування його в нашому тестовому середовищі (SQL 2014) показує, що він працює!

Як SQL знає, щоб вирішити підзапит і видалити записи з table?

Відповіді:


14

Код, який subqueryви маєте у своєму коді, називається похідною таблицею . Це не базова таблиця, а таблиця, яка "живе" під час запуску запиту. Як і представлення (які також називаються переглянуті таблиці ) - а в останніх версіях CTE - це ще один, четвертий спосіб "визначення" таблиці всередині запиту - вони багато в чому схожі на таблицю. Ви можете selectз них, ви можете використовувати їх у fromабо вjoin до інших таблиць (базових чи ні!).

У деяких СУБД (не всі СУБД реалізували це однаково) ці таблиці / представлення можна оновити . І «оновлювані» означає , що ми можемо також update, insertв абоdelete з них.

Однак існують обмеження, і цього очікується. Уявіть, чи subqueryбуло поєднання 2 (або 17 таблиць). Що б deleteтоді означало? (з яких таблиць слід видалити рядки?) Оновлені погляди - справа дуже складна . Існує недавня (2012) книга, повністю на цю тему, написана Крісом Датеєм, добре відомим знавцем реляційної теорії: Перегляд оновлення та реляційної теорії .

Коли похідна таблиця (або представлення) є дуже простим запитом, як-от у неї є лише одна базова таблиця (можливо обмежена а WHERE), і ні GROUP BY, то кожен рядок похідної таблиці відповідає одному рядку в базовій базовій таблиці, так що це легко * оновити, вставити або видалити з цього.

Коли код всередині підзапиту є більш складним, це залежить від того, чи можна відстежувати / вирішувати рядки похідної таблиці / перегляду до рядків з однієї з базових базових таблиць.

Для SQL Server, ви можете прочитати в пункті оновлюваних уявлень в MSDN: CREATE VIEW.

Оновлені перегляди

Ви можете змінювати дані базової базової таблиці за допомогою перегляду, якщо виконуються такі умови:

  • Будь-які зміни, включаючи UPDATE, INSERTта DELETEзаяви, повинні посилатися на стовпці лише з однієї базової таблиці.

  • Стовпці, що змінюються у представленні даних, повинні безпосередньо посилатися на базові дані у стовпцях таблиці. Стовпці неможливо отримати жодним іншим способом, наприклад, за допомогою наступного:

  • Агрегатна функція: AVG, COUNT, SUM, MIN, MAX, GROUPING, STDEV, STDEVP, VAR, і VARP.

  • Обчислення. Стовпець не можна обчислити з виразу, який використовує інші стовпці. Стовпці, які сформовані з використанням набору операторів UNION, UNION ALL, CROSSJOIN, EXCEPT, і INTERSECT кількості до обчислення і також не оновлювані.

  • Стовпці модифікуються не впливає GROUP BY, HAVINGабо DISTINCTположення.

  • TOPне використовується ніде в select_statement перегляду разом із WITH CHECK OPTIONпунктом.

Попередні обмеження поширюються на будь-які підзапити в FROMпункті перегляду, так само як вони стосуються самого виду. Як правило, двигун бази даних повинен мати можливість однозначно відстежувати модифікації від визначення перегляду до однієї базової таблиці.


Насправді deleteлегше, менш складне, ніж update. Для SQL Server потрібні лише первинні ключі або інший спосіб визначити, які рядки базової таблиці потрібно видалити. Тому що updateіснує додаткове (досить очевидне) обмеження, яке ми не можемо оновити обчислений стовпець. Ви можете спробувати змінити запит, щоб зробити оновлення. Оновлення CreatedDateTime, ймовірно, спрацює нормально, але спроба оновити обчислений RowNumberстовпець призведе до помилки. І insertще складніше, оскільки нам доведеться надати значення для всіх стовпців базової таблиці, які не мають DEFAULTобмежень.


4

Це легко зрозуміти, дивлячись на план запитів. У вашому випадку план просто містить додатковий оператор проекту сегмента та послідовності для обробки номера рядка. Цей тип операцій працює лише тоді, коли SQL Server насправді може вирішити основну таблицю.

Видалення з підзапитів та CTE повністю підтримується та дуже ефективно, особливо для видалення дублікатів. Я також, здається, згадую його використання на старих версіях SQL Server.

Більше в моїй старій публікації блогу .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.