Wie schreibe ich eine SQL DELETE-Anweisung mit einer SELECT-Anweisung in die WHERE-Klausel?

78

Datenbank: Sybase Advantage 11

Bei meinem Versuch, Daten zu normalisieren, versuche ich, die Ergebnisse zu löschen, die ich aus dieser SELECTAussage erhalte :

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')
;

Dies ist die DELETEAussage, die ich mir ausgedacht habe:

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'))
;

Ich erhalte ständig diesen Fehler, wenn ich versuche, diese Anweisung auszuführen:

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.

Ich habe auch diese Aussage versucht:

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')
;

Was in ... endet:

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)

Könnte mir jemand helfen, eine DELETE-Abfrage richtig zu erstellen, die dazu führt, dass die richtigen Daten entfernt werden?

LuiCami
quelle
Worst-Case-Szenario: Können Sie eine temporäre Tabelle erstellen, in diese temporäre Tabelle AUSWÄHLEN, Ihre Löschung der temporären Tabelle hinzufügen und dann die temporäre Tabelle DROPEN?
PP.

Antworten:

140

Sie müssen den Primärschlüssel in Tabelle A identifizieren, um den richtigen Datensatz zu löschen. Der Primärschlüssel kann eine einzelne Spalte oder eine Kombination mehrerer Spalten sein, die eine Zeile in der Tabelle eindeutig identifiziert. Wenn kein Primärschlüssel vorhanden ist, kann die ROWID-Pseudospalte als Primärschlüssel verwendet werden.

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'));
Alex W.
quelle
1
Danke Alex für die schnelle Antwort. @AlexW Ich denke du hast den Nagel auf den Kopf getroffen. Die Funktionsweise dieser Tabelle besteht darin, dass die Entitätsnummer mit vielen Datensätzen verknüpft ist und als solche kein Primärschlüssel an und für sich ist. Ich habe keine Erfahrung mit der Verwendung der ROWID-Pseudospalte in Advantage. Können Sie erklären, wie dies verwendet wird? Danke noch einmal.
LuiCami
Hallo, vielleicht haben Sie bereits Informationen zur ROWID gefunden, aber der folgende Artikel war hilfreich für mich, um die Funktionalität hinter dieser Pseudospalte zu verstehen. devzone.advantagedatabase.com/dz/webhelp/Advantage10/…
hel
Wenn der Primärschlüssel also eine Reihe von Spalten ist, kann ich sie einfach durch Kommas getrennt anstelle von ROWID trennen?
Aroma
Bei einer Reihe von Spalten ist dies komplizierter. Wenn der DB-Server "Zeilentyp" als Datentyp unterstützt, können Sie dies mit WHERE ROW (c1, c2, ..) IN (SELECT ROW (x, y, z) FROM ...) tun. Wenn die Datenbank jedoch den ROW-Typ nicht unterstützt, müssen die Spalten in einen Einzelwertausdruck konvertiert werden, z. B. Verkettung von Spalten.
Alex W
26

Ihre zweite DELETEAnfrage war fast richtig. Stellen Sie einfach sicher, dass Sie den Tabellennamen (oder einen Alias) dazwischen setzen DELETEundFROM angeben, aus welcher Tabelle Sie löschen möchten. Dies ist einfacher als die Verwendung einer verschachtelten SELECTAnweisung wie in den anderen Antworten.

Korrigierte Abfrage (Option 1: Verwenden des vollständigen Tabellennamens):

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')

Korrigierte Abfrage (Option 2: Verwenden eines Alias):

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')

Weitere Beispiele hier:
Löschen mit INNER JOIN mit SQL Server

MarredCheese
quelle
18

Sollten Sie nicht haben:

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

Jetzt haben Sie nur noch ein WO ohne Vergleich:

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

Ihre letzte Anfrage würde also so aussehen.

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')
)
Epoche
quelle
Danke für die Antwort. Es scheint, als würde ich beim Zählen der zu löschenden Daten weit mehr Datensätze als ursprünglich vorgesehen haben (4598021 statt 32061). Ich habe definitiv mein Fachwissen dazu erreicht. Kennen Sie den Grund dafür? Meine count-Anweisung sah folgendermaßen aus: 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) NICHT IN (8,9,10) ODER q.memotext NICHT WIE '% /% /%') UND (u.FldFormat = 'Datum'));
LuiCami
4

In diesem Szenario:

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'));

Vermissen Sie nicht die Spalte, mit der Sie vergleichen möchten? Beispiel:

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'));    

Ich gehe davon aus, dass es sich um diese Spalte handelt, da Sie in Ihrer select-Anweisung aus derselben Tabelle auswählen, aus der Sie mit dieser Spalte löschen möchten.

Andres
quelle
Danke für die Antwort. Es scheint, als würde ich beim Zählen der zu löschenden Daten weit mehr Datensätze als ursprünglich vorgesehen haben (4598021 statt 32061). Ich habe definitiv mein Fachwissen dazu erreicht. Kennen Sie den Grund dafür? Meine count-Anweisung sah folgendermaßen aus: 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) NICHT IN (8,9,10) ODER q.memotext NICHT WIE '% /% /%') UND (u.FldFormat = 'Datum'));
LuiCami
Die große Anzahl ist sicherlich möglich, wenn die Entitätsnummer in Tabelle A nicht eindeutig (oder primär) ist. Beispielsweise kann es mehrere Zeilen geben, deren Entitätsnummer gleich 1 ist, von denen jedoch nur eine der Verknüpfungsbedingung entspricht. Die Bedingung 'entitynum IN (SELECT ...)' gibt jedoch alle Zeilen zurück, wobei entitynum gleich 1 ist.
Alex W
Die Auswahl, die ich verwendet hatte, war die folgende, um alle den Datensätzen zugeordneten Spalten abzurufen. Der Primärschlüssel ist immer noch die q.entitynum: SELECT q. * FROM tableA q INNER JOIN tableB u on (u.qlabel = q .entityrole AND u.fieldnum = q.fieldnum) WO (LÄNGE (q.memotext) NICHT IN (8,9,10) ODER q.memotext NICHT WIE '% /% /%') UND (u.FldFormat = 'Datum ')
LuiCami
1

Hab so etwas mal gemacht:

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
Matthew Hub
quelle