Як написати оператор SQL DELETE з оператором SELECT у реченні WHERE?


80

База даних: Sybase Advantage 11

Прагнучи нормалізувати дані, я намагаюся видалити результати, отримані з цього SELECTтвердження:

SELECT tableA.entitynum
FROM tableA q
INNER JOIN tableB u on (u.qlabel = q.entityrole AND u.fieldnum = q.fieldnum) 
WHERE (LENGTH(q.memotext) NOT IN (8,9,10) 
OR q.memotext NOT LIKE '%/%/%')
AND (u.FldFormat = 'Date')
;

Це DELETEтвердження, яке я придумав:

DELETE FROM tableA
WHERE (SELECT q.entitynum
FROM tableA q
INNER JOIN tableB u on (u.qlabel = q.entityrole AND u.fieldnum = q.fieldnum) 
WHERE (LENGTH(q.memotext) NOT IN (8,9,10) 
OR q.memotext NOT LIKE '%/%/%')
AND (u.FldFormat = 'Date'))
;

Я постійно отримую цю помилку, коли намагаюся запустити таке твердження:

ERROR IN SCRIPT: poQuery: Error 7200:  AQE Error:  State = S0000;   NativeError = 2124;
[iAnywhere Solutions][Advantage SQL Engine]Invalid operand for operator: = Boolean value
cannot be operated with non-Boolean value.

Я також спробував це твердження:

DELETE FROM tableA 
INNER JOIN tableB u on (u.qlabel = tableA.entityrole AND u.fieldnum = tableA.fieldnum) 
WHERE (LENGTH(q.memotext) NOT IN (8,9,10) 
OR tableA.memotext NOT LIKE '%/%/%')
AND (u.FldFormat = 'Date')
;

В результаті чого:

ERROR IN SCRIPT: poQuery: Error 7200:  AQE Error:  State = 42000;   NativeError = 2117;
[iAnywhere Solutions][Advantage SQL Engine] Unexpected token: INNER -- Expecting semicolon.
-- Location of error in the SQL statement is: 23 (line: 2 column: 1)

Чи може хтось допомогти мені у правильній побудові запиту DELETE, що призведе до видалення належних даних?


Найгірший сценарій - чи можете ви створити тимчасову таблицю, ВИБРАТИ в цю тимчасову таблицю, чи видалити ваше приєднання до тимчасової таблиці, а потім ВИДАЛИТИ тимчасову таблицю?
ПП.

Відповіді:


143

Вам потрібно визначити первинний ключ у таблиці А, щоб видалити правильний запис. Первинний ключ може бути одним стовпцем або комбінацією з декількох стовпців, що однозначно ідентифікує рядок у таблиці. Якщо первинного ключа немає, тоді як первинний ключ може використовуватися псевдостолбік ROWID.

DELETE FROM tableA
WHERE ROWID IN 
  ( SELECT q.ROWID
    FROM tableA q
      INNER JOIN tableB u on (u.qlabel = q.entityrole AND u.fieldnum = q.fieldnum) 
    WHERE (LENGTH(q.memotext) NOT IN (8,9,10) OR q.memotext NOT LIKE '%/%/%')
      AND (u.FldFormat = 'Date'));

1
Дякую Алекс за швидку відповідь. @AlexW Я думаю, ти вдарив цвях по голові. Ця таблиця працює таким чином, що EntityNum пов'язаний з багатьма записами і як такий не є первинним ключем сам по собі. У мене немає досвіду використання псевдоколонки ROWID у Advantage. Не могли б ви пояснити, як цим користуватися? Знову дякую.
LuiCami

Привіт, Можливо, ти вже знайшов інформацію щодо ROWID, але нижченаведена стаття допомогла мені зрозуміти функціональність цієї псевдоколонки. devzone.advantagedatabase.com/dz/webhelp/Advantage10/…
hel

отже, якщо первинний ключ - це набір стовпців, я можу просто розділити їх комами замість ROWID?
аромат

Це складніше з набором стовпців. Якщо сервер БД підтримує "тип рядка" як тип даних, ви можете зробити це, наприклад, WHERE ROW (c1, c2, ..) IN (SELECT ROW (x, y, z) FROM ...). Однак, якщо БД не підтримує тип ROW, то стовпці повинні бути перетворені в єдиний вираз значення, наприклад - конкатенація стовпців.
Alex W

27

Ваш другий DELETEзапит був майже правильним. Просто не забудьте помістити назву таблиці (або псевдонім) між DELETEіFROM вказати, з якої таблиці ви видаляєте. Це простіше, ніж використання вкладеного SELECTвисловлювання, як у інших відповідях.

Виправлений запит (варіант 1: використання повного імені таблиці):

DELETE tableA
FROM tableA
INNER JOIN tableB u on (u.qlabel = tableA.entityrole AND u.fieldnum = tableA.fieldnum) 
WHERE (LENGTH(tableA.memotext) NOT IN (8,9,10)
OR tableA.memotext NOT LIKE '%/%/%')
AND (u.FldFormat = 'Date')

Виправлений запит (варіант 2: використання псевдоніма):

DELETE q
FROM tableA q
INNER JOIN tableB u on (u.qlabel = q.entityrole AND u.fieldnum = q.fieldnum) 
WHERE (LENGTH(q.memotext) NOT IN (8,9,10) 
OR q.memotext NOT LIKE '%/%/%')
AND (u.FldFormat = 'Date')

Інші приклади тут:
Як видалити за допомогою INNER JOIN із SQL Server?


19

Чи не мали б ви:

DELETE FROM tableA WHERE entitynum IN (...your select...)

Тепер у вас просто є ДЕ, де немає порівняння:

DELETE FROM tableA WHERE (...your select...)

Отже, ваш остаточний запит буде виглядати так;

DELETE FROM tableA WHERE entitynum IN (
    SELECT tableA.entitynum FROM tableA q
      INNER JOIN tableB u on (u.qlabel = q.entityrole AND u.fieldnum = q.fieldnum) 
    WHERE (LENGTH(q.memotext) NOT IN (8,9,10) OR q.memotext NOT LIKE '%/%/%')
      AND (u.FldFormat = 'Date')
)

дякую за відповідь. Здається, що коли я підраховую те, що збирався видалити, у підсумку отримую набагато більше записів, ніж передбачалося спочатку (4598021 замість 32061). Я безумовно досяг свого рівня знань з цього питання. Чи знаєте ви, чому це могло бути так? Мій оператор count виглядав так: SELECT COUNT (*) FROM tableA WHERE entitynum IN (SELECT q.entitynum FROM tableA q INNER JOIN tableB u on (u.qlabel = q.entityrole AND u.fieldnum = q.fieldnum) WHERE (LENGTH) (q.memotext) НЕ ВХОДИТЬ (8,9,10) АБО q.memotext НЕ ПОДОБАЄТЬСЯ '% /% /%') І (u.FldFormat = 'Дата'));
LuiCami

4

у цьому сценарії:

DELETE FROM tableA
WHERE (SELECT q.entitynum
FROM tableA q
INNER JOIN tableB u on (u.qlabel = q.entityrole AND u.fieldnum = q.fieldnum) 
WHERE (LENGTH(q.memotext) NOT IN (8,9,10) 
OR q.memotext NOT LIKE '%/%/%')
AND (u.FldFormat = 'Date'));

Вам не бракує стовпця, з яким Ви хочете порівняти? приклад:

DELETE FROM tableA
WHERE entitynum in (SELECT q.entitynum
FROM tableA q
INNER JOIN tableB u on (u.qlabel = q.entityrole AND u.fieldnum = q.fieldnum) 
WHERE (LENGTH(q.memotext) NOT IN (8,9,10) 
OR q.memotext NOT LIKE '%/%/%')
AND (u.FldFormat = 'Date'));    

Я припускаю, що це той стовпець, оскільки у вашому операторі select ви вибираєте з тієї ж таблиці, яку ви хочете видалити за допомогою цього стовпця.


дякую за відповідь. Здається, що коли я підраховую те, що збирався видалити, у підсумку отримую набагато більше записів, ніж передбачалося спочатку (4598021 замість 32061). Я безумовно досяг свого рівня знань з цього питання. Чи знаєте ви, чому це могло бути так? Мій оператор count виглядав так: SELECT COUNT (*) FROM tableA WHERE entitynum IN (SELECT q.entitynum FROM tableA q INNER JOIN tableB u on (u.qlabel = q.entityrole AND u.fieldnum = q.fieldnum) WHERE (LENGTH) (q.memotext) НЕ ВХОДИТЬ (8,9,10) АБО q.memotext НЕ ПОДОБАЄТЬСЯ '% /% /%') І (u.FldFormat = 'Дата'));
LuiCami

Великий підрахунок, безумовно, можливий, якщо entitynum не є унікальним (або первинним ключем) у ТаблиціA. Наприклад, може бути кілька рядків з номером об'єкта, рівним 1, але лише один з них відповідає умові об'єднання. Однак умова 'entitynum IN (SELECT ...)' поверне всі рядки з entitynum рівним 1.
Alex W

Виділення, яке я використовував, було наступним, щоб захопити всі стовпці, пов’язані із записами, первинним ключем все ще залишається q.entitynum: SELECT q. * ІЗ таблиціA q ВНУТРІШНЄ ПРИЄДНАННЯ tableB u on (u.qlabel = q .entityrole І u.fieldnum = q.fieldnum) ДЕ (LENGTH (q.memotext) НЕ В (8,9,10) АБО q.memotext НЕ ПОДОБАЄТЬСЯ '% /% /%') І (u.FldFormat = 'Дата ')
LuiCami

1

Колись зробив щось подібне:

CREATE TABLE exclusions(excl VARCHAR(250));
INSERT INTO exclusions(excl)
VALUES
       ('%timeline%'),
       ('%Placeholders%'),
       ('%Stages%'),
       ('%master_stage_1205x465%'),
       ('%Accessories%'),
       ('%chosen-sprite.png'),
('%WebResource.axd');
GO
CREATE VIEW ToBeDeleted AS 
SELECT * FROM chunks
       WHERE chunks.file_id IN
       (
       SELECT DISTINCT
             lf.file_id
       FROM LargeFiles lf
       WHERE lf.file_id NOT IN
             (
             SELECT DISTINCT
                    lf.file_id
             FROM LargeFiles lf
                LEFT JOIN exclusions e ON(lf.URL LIKE e.excl)
                WHERE e.excl IS NULL
             )
       );
GO
CHECKPOINT
GO
SET NOCOUNT ON;
DECLARE @r INT;
SET @r = 1;
WHILE @r>0

BEGIN
    DELETE TOP (10000) FROM ToBeDeleted;
    SET @r = @@ROWCOUNT  
END
GO
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.