2010-09-08 16 views
13

Tengo el siguiente código que funciona bien en MS SQL Server:Eliminar la combinación izquierda en Oracle 10g

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 

Básicamente, quiero borrar todos los sucesos que se pueden encontrar en grp y no tienen ningún equivalencia in my_data. Lamentablemente, no funciona en Oracle 10g. Intenté usar la sintaxis anterior para la combinación izquierda (+) pero tampoco funciona. De esta manera:

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 

Una cláusula IN haría obras si no dispone de varias teclas, pero no veo cómo podría usarlo con mis datos. ¿Entonces cual es la alternativa?

+0

SQL Server apoyo se une en eliminar y actualizar es una extensión no estándar para SQL. –

+0

Shannon Separación: MySQL también –

Respuesta

15

tablas y datos:

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. 

Uso de in. Nota No utilizar si los ID en la subconsulta pueden ser null. Not in de null nunca devuelve verdadero.

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 

Usando 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

Implementé las tres soluciones propuestas hasta ahora. el 'where not exists' es casi 3 veces más rápido que las soluciones' not in' y 'left join' en el caso preciso que lo probé en Oracle. No sé si alguna de esas soluciones sigue los estándares SQL, pero la solución 'where not exists' es la única que funciona tanto para Oracle como para MS SQL Server. Me sorprende que la solución 'no en 'se pueda usar con múltiples campos ya que no hay una asociación explícita. ¿Funciona porque comparten el mismo nombre? ¿Es posible hacer que funcione usando alias? –

+0

'not in' con varios campos está definido en algún estándar SQL (SQL-92?), Pero la última vez que lo comprobé no se había implementado en SQL Server. '(w, x, y, z) in (seleccione a, b, c, d desde ....)' toma la tupla en el lado izquierdo, '(w, x, y, z)' Y la comprueba contra cada fila (tupla) volvió en el lado derecho: 'w = a y x = b ey = c yz = d'. No depende de que los nombres sean los mismos). –

15

Shannon's solution es el camino a seguir: utilizar el operador NOT IN (o no existe).

Sin embargo, puede eliminar o actualizar una combinación en Oracle, pero la synthax no es lo mismo que 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 

Además, Oracle sólo se permitirá actualizar una unión si no hay ambigüedad en cuanto a qué fila de base accederá la declaración. En particular, Oracle no correrá el riesgo de una actualización o eliminación (la declaración fallará) si existe la posibilidad de que una fila aparezca dos veces en la combinación. En este caso, la eliminación sólo funcionará si hay una restricción única en my_data(id1, id2, id3, id4).

15

Si desea asegurarse de que no hay ambigüedad en lo que está siendo eliminada, podría cambiar Vincent's solution a:

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 
    ) 
Cuestiones relacionadas