tutorial portable mac developer descargar sql oracle oracle-sqldeveloper

portable - sql developer mac



insertar si no existe el orĂ¡culo (10)

Necesito poder ejecutar una consulta de Oracle que vaya a insertar varias filas, pero también comprueba si existe una clave principal y, si lo hace, se salta esa inserción. Algo como:

INSERT ALL IF NOT EXISTS( SELECT 1 WHERE fo.primary_key=''bar'' ) ( INSERT INTO schema.myFoo fo ( primary_key, value1, value2 ) VALUES (''bar'',''baz'',''bat'') ), IF NOT EXISTS( SELECT 1 WHERE fo.primary_key=''bar1'' ) ( INSERT INTO schema.myFoo fo ( primary_key, value1, value2 ) VALUES (''bar1'',''baz1'',''bat1'') ) SELECT * FROM schema.myFoo;

¿Es esto posible con Oracle?

Puntos de bonificación si me puede decir cómo hacerlo en PostgreSQL o MySQL.


Esta es una respuesta al comentario publicado por erikkallen:

No necesitas una tabla temporal. Si solo tiene algunas filas, (SELECT 1 FROM dual UNION SELECT 2 FROM dual) funcionará. ¿Por qué tu ejemplo daría ORA-0001? ¿No fusionaría tomaría el bloqueo de actualización en la clave de índice y no continuaría hasta que Sess1 se haya comprometido o revertido? - erikkallen

Bueno, pruébalo tú mismo y dime si recibes el mismo error o no:

SESS1:

create table t1 (pk int primary key, i int); create table t11 (pk int primary key, i int); insert into t1 values(1, 1); insert into t11 values(2, 21); insert into t11 values(3, 31); commit;

SESS2: insert into t1 values(2, 2);

SESS1:

MERGE INTO t1 d USING t11 s ON (d.pk = s.pk) WHEN NOT MATCHED THEN INSERT (d.pk, d.i) VALUES (s.pk, s.i);

SESS2: commit;

SESS1: ORA-00001


Esto solo se inserta si el elemento que se va a insertar ya no está presente.

Funciona igual que:

if not exists (...) insert ...

en T-SQL

insert into destination (DESTINATIONABBREV) select ''xyz'' from dual left outer join destination d on d.destinationabbrev = ''xyz'' where d.destinationid is null;

puede no ser bonita, pero es útil :)


La declaración se llama MERGE. Búscalo, soy muy flojo.

Tenga cuidado, sin embargo, que MERGE no es atómico, lo que podría causar el siguiente efecto (gracias, Marius):

SESS1:

create table t1 (pk int primary key, i int); create table t11 (pk int primary key, i int); insert into t1 values(1, 1); insert into t11 values(2, 21); insert into t11 values(3, 31); commit;

SESS2: insert into t1 values(2, 2);

SESS1:

MERGE INTO t1 d USING t11 s ON (d.pk = s.pk) WHEN NOT MATCHED THEN INSERT (d.pk, d.i) VALUES (s.pk, s.i);

SESS2: commit;

SESS1: ORA-00001


Llegando tarde a la fiesta, pero ...

Con Oracle 11.2.0.1 hay una sugerencia semántica que puede hacer esto: IGNORE_ROW_ON_DUPKEY_INDEX

Ejemplo:

insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(customer_orders,pk_customer_orders) */ into customer_orders (order_id, customer, product) values ( 1234, 9876, ''K598'') ;

ACTUALIZACIÓN : aunque esta sugerencia funciona (si la deletreas correctamente), hay mejores enfoques que no requieren Oracle 11R2:

Primera aproximación-traducción directa de la sugerencia semántica anterior:

begin insert into customer_orders (order_id, customer, product) values ( 1234, 9876, ''K698'') ; commit; exception when DUP_VAL_ON_INDEX then ROLLBACK; end;

Segundo enfoque, mucho más rápido que las dos sugerencias anteriores cuando hay mucha controversia:

begin select count (*) into l_is_matching_row from customer_orders where order_id = 1234 ; if (l_is_matching_row = 0) then insert into customer_orders (order_id, customer, product) values ( 1234, 9876, ''K698'') ; commit; end if; exception when DUP_VAL_ON_INDEX then ROLLBACK; end;


Podemos combinar DUAL y NOT EXISTS para archivar su requerimiento:

INSERT INTO schema.myFoo ( primary_key, value1, value2 ) SELECT ''bar'', ''baz'', ''bat'' FROM DUAL WHERE NOT EXISTS ( SELECT 1 FROM schema.myFoo WHERE primary_key = ''bar'' );


Si NO desea fusionarse desde otra tabla, sino insertar datos nuevos ... se me ocurrió esto. ¿Hay quizás una mejor manera de hacer esto?

MERGE INTO TABLE1 a USING DUAL ON (a.C1_pk= 6) WHEN NOT MATCHED THEN INSERT(C1_pk, C2,C3,C4) VALUES (6, 1,0,1);


Si ese código está en el cliente, entonces tienes muchos viajes al servidor para eliminar eso.

Inserta todos los datos en una tabla temportary di T con la misma estructura que myFoo

Entonces

insert myFoo select * from t where t.primary_key not in ( select primary_key from myFoo)

Esto también debería funcionar en otras bases de datos. He hecho esto en Sybase.

No es lo mejor si se insertan muy pocos de los nuevos datos, ya que ha copiado todos los datos a través del cable.


Si su tabla es "independiente" de otras (quiero decir, no activará una eliminación en cascada o no establecerá ninguna relación de claves foráneas con nulo), un buen truco podría ser primero BORRAR la fila y luego INSERTARla de nuevo. Podría ser así:

ELIMINAR FROM MyTable WHERE prop1 = ''aaa''; // ¡suponiendo que seleccionará como máximo una fila!

INSERT INTO MyTable (prop1, ...) VALUES (''aaa'', ...);

Si estás eliminando algo que no existe, nada sucederá.


INSERT INTO schema.myFoo ( primary_key , value1 , value2 ) SELECT ''bar1'' AS primary_key ,''baz1'' AS value1 ,''bat1'' AS value2 FROM DUAL WHERE (SELECT 1 AS value FROM schema.myFoo WHERE LOWER(primary_key) =''bar1'' AND ROWNUM=1) is null;


DECLARE tmp NUMBER(3,1); BEGIN SELECT COUNT(content_id) INTO tmp FROM contents WHERE (condition); if tmp != 0 then INSERT INTO contents VALUES (...); else INSERT INTO contents VALUES (...); end if; END;

Usé el código de arriba. Es largo, pero, simple y funcionó para mí. Similar, al código de Micheal.