2010-09-08 3 views
13

Ich habe den folgenden Code, der in MS SQL Server funktioniert gut:mit Left Löschen in Oracle 10g Registriert

delete grp 
from grp 
left join my_data 
on grp.id1 = my_data.id1 
and grp.id2 = my_data.id2 
and grp.id3 = my_data.id3 
and grp.id4 = my_data.id4 
where my_data.id1 is NULL 

Grundsätzlich möchte ich alle Vorkommen löschen, die in grp gefunden werden kann, und haben keine Äquivalenz in my_data. Leider funktioniert es in Oracle 10g nicht. Ich habe versucht, die alte Syntax für Links Join (+) zu verwenden, aber es funktioniert auch nicht. Wie folgt aus:

delete grp 
from grp, 
my_data 
where grp.id1 = my_data.id1 (+) 
and grp.id2 = my_data.id2 (+) 
and grp.id3 = my_data.id3 (+) 
and grp.id4 = my_data.id4 (+) 
and my_data.id1 is NULL 

A IN Klausel würde funktioniert, wenn ich nicht mehrere Schlüssel hatte, aber ich sehe nicht, wie ich es mit meinen Daten nutzen könnten. Also, was ist die Alternative?

+0

SQL Server unterstützt Joins in delete und update ist eine nicht standardmäßige Erweiterung von SQL. –

+0

Shannon Severance: MySQL zu –

Antwort

15

Tabellen und Daten:

SQL> create table grp (id1 number null, id2 number null, id3 number null, id4 number null);  
Table created. 

SQL> create table my_data (id1 number null, id2 number null, id3 number null, id4 number null); 

Table created. 

SQL> insert into grp values (1, 2, 3, 4); 

1 row created. 

SQL> insert into grp values (10, 20, 30, 40); 

1 row created. 

SQL> insert into grp values (1, 2, 30, 40); 

1 row created. 

SQL> insert into my_data values (1, 2, 3, 4); 

1 row created. 

SQL> commit; 

Commit complete. 

in verwenden. Hinweis Verwenden Sie nicht, wenn die IDs in der Unterabfrage null sein können. Not in von null gibt nie wahr zurück.

SQL> delete grp where (id1, id2, id3, id4) not in (select id1, id2, id3, id4 from my_data); 

2 rows deleted. 

SQL> select * from grp; 

     ID1  ID2  ID3  ID4 
---------- ---------- ---------- ---------- 
     1   2   3   4 

exists

SQL> rollback; 

Rollback complete. 

SQL> delete grp where not exists (select * from my_data where grp.id1 = my_data.id1 and grp.id2 = my_data.id2 and grp.id3 = my_data.id3 and grp.id4 = my_data.id4); 

2 rows deleted. 

SQL> select * from grp; 

     ID1  ID2  ID3  ID4 
---------- ---------- ---------- ---------- 
     1   2   3   4 

SQL> 
+0

Ich implementierte alle drei bisher vorgeschlagenen Lösungen. das 'where not exists' ist fast 3-mal schneller als die' not in'- und 'left join'-Lösungen in dem genauen Fall, in dem ich es auf Oracle getestet habe. Ich weiß nicht, ob irgendwelche dieser Lösungen den SQL-Standards folgen, aber die "where not exists" -Lösung ist die einzige, die sowohl für Oracle als auch für MS SQL Server funktioniert. Ich bin überrascht, dass die "nicht in" Lösung mit mehreren Feldern verwendet werden kann, da es keine explizite Assoziation gibt. Funktioniert es, weil sie den gleichen Namen haben? Ist es möglich, dass es mit Alias ​​funktioniert? –

+0

'nicht in' mit mehreren Feldern ist in einigen SQL-Standard (SQL-92?) Definiert, aber zuletzt überprüft wurde nicht in SQL Server implementiert worden. '(w, x, y, z) in (wähle a, b, c, d aus ....)' nimmt das Tupel auf der linken Seite, '(w, x, y, z)' Und prüft es Jede Zeile (Tupel) wird auf der rechten Seite zurückgegeben: 'w = a und x = b und y = c und z = d '. Es kommt nicht darauf an, dass die Namen gleich sind.) –

15

Shannon's solution Verwendung ist der Weg zu gehen: den Operator nicht verwendet wird (oder NICHT VORHANDEN).

können Sie jedoch löschen oder in Oracle beitreten aktualisieren, aber die Synthax ist nicht das gleiche wie MS SQL Server:

SQL> DELETE FROM (SELECT grp.* 
    2     FROM grp 
    3     LEFT JOIN my_data ON grp.id1 = my_data.id1 
    4         AND grp.id2 = my_data.id2 
    5         AND grp.id3 = my_data.id3 
    6         AND grp.id4 = my_data.id4 
    7     WHERE my_data.id1 IS NULL); 

2 rows deleted 

Darüber hinaus wird nur Oracle können Sie eine Verknüpfung aktualisieren, wenn es keine Zweideutigkeit ist als Auf welche Basiszeile wird von der Anweisung zugegriffen. Insbesondere riskiert Oracle keine Aktualisierung oder Löschung (die Anweisung schlägt fehl), wenn die Möglichkeit besteht, dass eine Zeile zweimal in der Verknüpfung erscheint. In diesem Fall arbeiten die Lösch nur, wenn es eine UNIQUE-Einschränkung auf ist my_data(id1, id2, id3, id4).

15

Wenn Sie dort sicherstellen wollen, ist keine Mehrdeutigkeit in, was gelöscht ist wird, Sie Vincent's solution sich ändern könnte:

delete from grp where rowid in 
    (
    select 
     grp.rowid 
    from 
     grp left outer join my_data on 
      grp.id1 = my_data.id1 
     and grp.id2 = my_data.id2 
     and grp.id3 = my_data.id3 
     and grp.id4 = my_data.id4 
    where 
     my_data.id1 is NULL 
    )