Löschen von Datensätzen innerhalb eines Bereiches

Themen rund um den praktischen Einsatz von Firebird. Fragen zu SQL, Performance, Datenbankstrukturen, etc.

Moderator: thorben.braun

Antworten
Groffy
Beiträge: 78
Registriert: Do 12. Apr 2018, 23:14

Ich möchte die jeweils ersten n Datensätze löschen. Die Tabelle hat einen Primärindex ID. Mein erster Versuch :

Code: Alles auswählen

delete from TABELLE where ID in (select ID from TABELLE order by ID rows 1 to n)
liefert ein für mich überraschendes Ergebnis - es werden alle Datensätze gelöscht.

Gebe ich das select statement getrennt ein

Code: Alles auswählen

select ID from TABELLE order by ID rows 1 to n
erhalte ich wie erwartet die ID Werte der ersten n Datensätze


Wo ist mein Fehler? Wie geht es richtig?



Gruß Ulrich
bfuerchau
Beiträge: 485
Registriert: Mo 7. Mai 2018, 18:09
Kontaktdaten:

Ich denke, das must du in einer Prozedur selber erledigen (geht auch per Execute Block).
Das Problem ist, das der Select je Satz ausgeführt wird, also nicht statisch ist.
Nach dem Delete des 1 Satzes liefert der Select wieder 10 Zeilen.
In einer Prozedur kannst du dir diese 10 Id's merken und anschließend genau diese dann per Delete löschen.
Auch dabei gilt, wenn du den Select in einer Schleife durchführst ändert sich wieder laufend das Ergebnis.
Wenn deine ID's aufsteigend sind, kannst du Max(Id) verwenden:

execute block
declare mId integer;
begin;
select max(id) into mId
from (select id from mytable order by id rows 1 to n);
delete from mytable where id <= mId;
end;

Die Syntax erhebt nun keinen Anspruch auf Vollständig- und Richtigkeit.
Sie soll nur eine Idee zur Lösung beitragen.
Benutzeravatar
andi
Beiträge: 12
Registriert: Fr 13. Mär 2020, 16:26

Hi,

möglicherweise funktioniert dies:

DELETE FROM <tablename>
ORDER BY ID
ROWS 1 to 10

Sollte laut Firebird-Doku möglich sein: https://firebirdsql.org/refdocs/langref ... elete.html

LG, Andi
Groffy
Beiträge: 78
Registriert: Do 12. Apr 2018, 23:14

Hallo Andi,

diese Variante funktioniert, ich war nur überrascht, daß das subselect in der where clause nicht wie erwartet funktioniert. Ich denke es ist so wie bfuerchau es vermutet. Es ist wie eine while schleife in der man während des Schleifendurchlaufes die Anzahl der Elemente verändert.


Beste Grüße Ulrich
Benutzeravatar
andi
Beiträge: 12
Registriert: Fr 13. Mär 2020, 16:26

Hallo Ulrich,

ja das ist von Datenbank zu Datenbank unterschiedlich (Oracle verhält sich anders als MS-SQL und teilweise auch Unterschiede zwischen den einzelnen Versionen von Firebird), wobei aber bei jeder Datenbank mit folgendem SQL und Subselect Deine Abfrage funktionieren sollte:

delete from <tablename>
where ID = ANY
( select ID from <tablename> order by 1 rows 1 to n)

Du musst ein ANY verwenden - eines der wenigen Situationen in denen ich das nutzten kann. Mit ANY wird das Subselect erst ausgeführt, und dann anschließend der Hauptabfrage zugeführt, im Falle von Deiner Abfrage, hat dies mein Vorredner schon bestens erläutert.

LG, Andi
bfuerchau
Beiträge: 485
Registriert: Mo 7. Mai 2018, 18:09
Kontaktdaten:

Sobald eine Where-Klausel beim Delete verwendet wird, muss diese je Zeile geprüft werden.
Ein "where column = any (select ...)" ist i.Ü. identisch zu "where column in (select ...)". Beide prüfen, ob einer der gefunden Werte dem Vergleich entspricht.
Erst wenn ein anderer Operator verwendet wird komnmt es zum Unterschied, da der "in"-Operator dem "= any" entspricht. Alterantiv kann "in" aber auch eine Konstantenliste darstellen.

Aber den "Order by" des Delete hatte ich vollkommen verdrängt.
Benutzeravatar
andi
Beiträge: 12
Registriert: Fr 13. Mär 2020, 16:26

Hast Du das mit ANY überprüft. Bei mir funktioniert dies mit ANY - er werden nur die entsprechenden Zeilen aus der Unterabfrage gelöscht.

Code: Alles auswählen

delete from <tablename>
where ID in ( select ID
              from <tablename>
              order by ID
              rows 1 to n)
Hier werden bei mir in einer Testtabelle in FB alle Datensätze gelöscht!

Code: Alles auswählen

delete from <tablename>
where ID = ANY ( select ID
                 from <tablename>
                 order by 1
                 rows 1 to 10)
Hier werden bei mir in einer Testtabelle in FB nur die ersten 10 Datensätze gelöscht!
bfuerchau
Beiträge: 485
Registriert: Mo 7. Mai 2018, 18:09
Kontaktdaten:

Das hängt von der Implemantation ab.
Richtig ist das nicht (SQL-Standard), da eine Where-Klausel immer den aktuellen Satz betreffen muss mnit ggf. Wiederholng der Where-Klausel.
Ich arbeite viel mit der DB2/400 (DB2 for i), da ist das nur u.U. so. Wenn man sich nicht darauf verlassen kann, taigt das nichts. Ein Optimizer kann sich das nächse mal anders entscheiden und man wundert sich.
Antworten