web-dev-qa-db-fra.com

Oracle sql fusionner pour insérer et supprimer mais pas mettre à jour

Existe-t-il un moyen d'utiliser la fusion Oracle pour insérer et supprimer sans mettre à jour?

J'ai une table représentant un ensemble de valeurs liées à une seule ligne dans une autre table. Je pourrais changer l'ensemble des valeurs en les supprimant toutes et en rajoutant le nouvel ensemble, ou en en supprimant certaines de manière sélective et en ajoutant d'autres, mais je suis intéressé à en faire une seule déclaration si possible.

Voici un exemple de travail avec update. Afin de faire ce travail, j'ai dû ajouter dummy afin qu'une colonne soit disponible pour la mise à jour qui n'était pas dans la condition on. Existe-t-il un moyen de ne supprimer et insérer que sans colonne factice à mettre à jour?

Aucune colonne de la condition on ne peut figurer dans la liste update set même si elle n'est pas réellement mise à jour.

create table every_value ( the_value varchar2(32) );
create table paired_value ( the_id number, a_value varchar2(32) , dummy number default 0 );
-- the_id is a foreign_key to a row in another table

insert into every_value ( the_value ) values ( 'aaa' );
insert into every_value ( the_value ) values ( 'abc' );
insert into every_value ( the_value ) values ( 'ace' );
insert into every_value ( the_value ) values ( 'adg' );
insert into every_value ( the_value ) values ( 'aei' );
insert into every_value ( the_value ) values ( 'afk' );

-- pair ace and afk with id 3
merge into paired_value p using every_value e
on ( p.the_id = 3 and p.a_value = e.the_value )
when matched then update set dummy=dummy+1
delete where a_value not in ('ace','afk')
when not matched then insert (the_id,a_value)
values (3,e.the_value)
where e.the_value in ('ace','afk');

-- pair ace and aei with id 3
-- should remove afk, add aei, do nothing with ace
merge into paired_value p using every_value e
on ( p.the_id = 3 and p.a_value = e.the_value )
when matched then update set dummy = dummy+1
delete where a_value not in ('ace','aei')
when not matched then insert (the_id,a_value)
values (3,e.the_value)
where e.the_value in ('ace','aei');

-- pair aaa and adg with id 4
merge into paired_value p using every_value e
on ( p.the_id = 4 and p.a_value = e.the_value )
when matched then update set dummy = dummy+1
delete where a_value not in ('aaa','adg')
when not matched then insert (the_id,a_value)
values (4,e.the_value)
where e.the_value in ('aaa','adg');

select * from paired_value;

J'ai essayé ceci dans Oracle 10g et, avec ce sqlfiddle , Oracle 11g.

11
drawnonward

Non, vous ne pouvez pas supprimer les lignes qui n'ont pas été mises à jour par la commande de fusion.
Voici la documentation: http://docs.Oracle.com/cd/B28359_01/server.111/b28286/statements_9016.htm

Spécifiez la clause DELETE where_clause pour nettoyer les données d'une table alors que remplir ou mettre à jour. Les seules lignes affectées par cette clause sont les lignes de la table de destination mises à jour par la fusion opération. La condition DELETE WHERE évalue la valeur mise à jour, pas la valeur d'origine évaluée par UPDATE SET ... WHERE état. Si une ligne de la table de destination correspond à DELETE condition mais n'est pas inclus dans la jointure définie par la clause ON, alors il n'est pas supprimé. Tous les déclencheurs de suppression définis sur la cible la table sera activée pour chaque suppression de ligne.

Cela signifie que les lignes doivent être mises à jour. Cependant, vous n’avez pas besoin de mettre à jour toutes les lignes, après UPDATE, utilisez la même clause WHERE que celle que vous utilisez après DELETE.

when matched then update set dummy=dummy
    where a_value not in ('ace','afk')
delete 
    where a_value not in ('ace','afk')
15
krokodilko

J'ai trouvé que vous pouvez définir la colonne sur elle-même:

MERGE ...
WHEN MATCHED THEN 
   UPDATE SET a_value = a_value WHERE a_value not in ('ace','afk')
   DELETE WHERE a_value not in ('ace','afk')

Cela annule le besoin de la colonne factice. 

1
datico