[PL/SQL] Delete conditionnel

Bonjour à tous !

Petit copier / collé d’un ami grand lecteur de la zone, qu’à son travail ils sont méchant et la zone qu’elle est bloquée :slight_smile:


Salut tout le monde,
J’ai une petite question sur du code pl/sql ^^. Je vous explique ce que je veux faire :

J’ai 2 tables :

  • shippings, clé primaire : shipping_code
  • packing, clé primaire : (shipping_code, pack_code)
    Pour une shipping il y a 1 à n packing associé.
    J’ai une procédure qui efface des lignes de la table packing mais qui n’efface pas forcément toutes les packings associées à une shipping.
    J’ai donc besoin de vérifier si pour une liste de shipping_code donnée (obtenue via un select) il reste (ou pas) des packings associés. Et je dois ensuite effacer les lignes de la table shippings qui n’ont plus de packings associés.

D’après mes recherches, une solution est d’utiliser les curseurs avec un truc du genre :

[code]DECLARE
cursor num_shipping is
mon_select_qui_recupere_les_shipping_code;
num1 integer;
num2 integer;

BEGIN
open num_shipping;
Loop
Fetch num_shipping into num1;
select count (*) into num2 from packing where shipping_code = num1;
if (num2 = 0)
then
delete from shippings where shipping_code = num1;
end if;
End Loop;
close num_shipping;

END;[/code]

Voilà, si l’un d’entre vous a le temps de jeter un coup d’oeil et de me dire si ça semble correct ou non par
rapport à ce que je cherche à faire, ce serait sympa.
Si je me suis mal expliqué n’hésites pas à me demander.
Merci d’avance.


Et je vous remercie également par avance !

Bonne journée.

Euh, j’ai pas trop saisie, tu voulais pas dire que t’efface un shipping, et donc va t’effacer tous tes packing ?
Parce que je comprends comme ca, et du coup, j’aurais paramétré la table avec l’option Supression en cascade. Et du coup pas besoin de faire une procédure stocké complexe. Tu fais juste un delete de ta ligne de ta table Shipping et il te supprime comme un grand tous les packing associés à condition d’avoir déclaré ton shipping_code comme étant une clé étrangère dans ta table packing.

Après, j’imagine que c’est du Oracle et non du SQL Server ?

Supression en cascade = MEGA EVIL

Si il y a bien un truc qui trouvera jamais sa place dans une de mes DB c’est bien ce truc. C’est la recette parfaite pour faire “J’efface une colonne”… 5 minutes plus tard … “tain merde ou sont passees toutes mes donnees? mais! j’avais une base de donnée AAAAAAAAAAAARGH!”.

heu pourquoi faire simple quand on peut faire compliquer. En SQL, même pas en PL/SQL:

delete from shippings where shipping_code IN ( select shipping_code from packing having count(*)=0 ) and shipping_code IN (mon_select_qui_recupere_les_shipping_code)

Mais quand je lis cette phrase sans lire ton code…

[quote=“Zerross, post:1, topic: 47137”]J’ai 2 tables :
J’ai une procédure qui efface des lignes de la table packing mais qui n’efface pas forcément toutes les packings associées à une shipping.
J’ai donc besoin de vérifier si pour une liste de shipping_code donnée (obtenue via un select) il reste (ou pas) des packings associés. Et je dois ensuite effacer les lignes de la table shippings qui n’ont plus de packings associés.[/quote]
…j’ai l’impression que ça sera plutôt quelque chose du style:

delete from shippings where shipping_code IN ( select shipping_code from packing minus select shipping_code from packing ) and shipping_code IN (mon_select_qui_recupere_les_shipping_code)

En tout cas les curseurs c’est à éviter autant que possible : c’est plus lent et ça complexifie pour rien.

Euhhhhhh, pourquoi pas tout simplement un truc du genre:

Ou alors c’est trop simple et ya un piege?

C’est moi qui ai demandé à Zerross de poster :slight_smile:
Merci d’avoir répondu si rapidement!

[quote=« MetalDestroyer, post:2, topic: 47137 »]Euh, j’ai pas trop saisie, tu voulais pas dire que t’efface un shipping, et donc va t’effacer tous tes packing ?
Parce que je comprends comme ca, et du coup, j’aurais paramétré la table avec l’option Supression en cascade. Et du coup pas besoin de faire une procédure stocké complexe. Tu fais juste un delete de ta ligne de ta table Shipping et il te supprime comme un grand tous les packing associés à condition d’avoir déclaré ton shipping_code comme étant une clé étrangère dans ta table packing.

Après, j’imagine que c’est du Oracle et non du SQL Server ?[/quote]
Oui c’est sur du Oracle et non je ne peux pas faire de cascade. C’est plus ou moins ce que faisait la procédure stockée jusqu’à présent et elle efface juste 20000 lignes en trop à chaque fois :crying:
En fait, je n’efface pas tous les colis (packing) d’une expédition (shipping) donc je ne peux pas me permettre une cascade ou un équivalent, je suis obligé d’aller vérifier que mon shipping_code n’est plus présent dans ma table packing.
Exemple pour illustrer :
J’ai 2 shippings > shipping 1 qui a les packings 1, 2, 3
shipping 2 qui a les packings 4, 5, 6
pour la shipping 1 j’efface tous les packings
pour la shipping 2 j’efface seulement le packing 5
Bah au moment de delete dans shippings faut que je delete seulement la shipping 1
Je sais pas si c’est plus clair ^^

[quote=« phili_b, post:4, topic: 47137 »]heu pourquoi faire simple quand on peut faire compliquer. En SQL, même pas en PL/SQL:

delete from shippings where shipping_code IN ( select shipping_code from packing having count(*)=0 ) and shipping_code IN (mon_select_qui_recupere_les_shipping_code)[/quote]
Effectivement… ça a l’air complètement pas bête ton code…
Je teste ça demain :cry:

[quote]delete from shippings where shipping_code IN ( select shipping_code from packing minus select shipping_code from packing ) and shipping_code IN (mon_select_qui_recupere_les_shipping_code)

En tout cas les curseurs c’est à éviter autant que possible : c’est plus lent et ça complexifie pour rien.[/quote]
Là par contre, je ne comprend pas ce que c’est sensé faire :x
Sinon c’est noté pour les curseurs!

edit : Pour répondre à Teejhan, je pourrais faire comme ça effectivement mais vu la taille des tables concernées ça ne serait pas très efficace je pense. En même temps je suis pas DBA ni développeur donc peut-être que j’évalue mal l’efficacité de la chose.

[quote=« GloP, post:3, topic: 47137 »]Supression en cascade = MEGA EVIL

Si il y a bien un truc qui trouvera jamais sa place dans une de mes DB c’est bien ce truc. C’est la recette parfaite pour faire « J’efface une colonne »… 5 minutes plus tard … « tain merde ou sont passees toutes mes donnees? mais! j’avais une base de donnée AAAAAAAAAAAARGH! ».[/quote]

Arf c’est si evil que ca ? Alors pourquoi l’avoir gardé ? :slight_smile: Il doit bien y servir à quelque chose ?

C’est l’equivalent d’un goto en base de donnee… oui des fois ca sert, la plupart du temps ca merite un coup de latte sur le derriere de la tete :slight_smile:

[quote=« GloP, post:3, topic: 47137 »]Supression en cascade = MEGA EVIL[/quote]Peut-être que le problème vient de l’utilisateur et non de l’outil. :slight_smile:

[quote=« Teejhan, post:5, topic: 47137 »]Euhhhhhh, pourquoi pas tout simplement un truc du genre:

DELETE FROM shippings WHERE shipping_code NOT IN (SELECT shipping_code FROM packing)

Ou alors c’est trop simple et ya un piege?[/quote]

c’est correct, par contre en fonction du nombre de millions de lignes retournées par « SELECT shipping_code FROM packing », ça peut être un poil gourmand.

donc je verrais plus un truc de ce genre:

DELETE FROM shippings WHERE shipping_code IN (select ta liste de codes) AND shipping_code NOT IN (SELECT shipping_code FROM packing WHERE shipping_code IN (select ta liste de codes) )

[quote]delete
from shippings
where shipping_code IN
(
select shipping_code
from packing
having count(*)=0
)
and shipping_code IN (mon_select_qui_recupere_les_shipping_code)


delete
from shippings
where shipping_code IN
(
select shipping_code
from packing
minus
select shipping_code
from packing
)
and shipping_code IN (mon_select_qui_recupere_les_shipping_code)[/quote]

Je crois que tu devrais te relire :slight_smile:

je savais pas ca… Tu as un peu plus de detail (j’avoue n’avoir que chercher 10sec sous google)? Le goto je sais (empilement memoire, lisibilite du code a chier… etc), mais les delete en cascade je vois pas le probleme, limite au contraire…

azacreel2, un delete en cascade en prod avec toutes tes contraintes d’intégrité, c’est la mort assurée à moyen terme ! :slight_smile:

Je ne l’utilise qu’en dév, quand je veux nettoyer un pays par exemple (et si on faisait disparaître la France de ma DB, hopla).

En prod, si t’as une personne qui l’applique sur un mauvais champ ou une mauvaise table, ça fait pschiiiittt comme disait l’autre (on a dit « pas de politique », oups :crying:). Et te voilà bon pour dépioussérer tes archive logs, ou ton backup

Pour exactement les memes raisons: tu fais une action et t’en as une autre, potentiellement catastrophique qui arrive sans que tu puisses savoir ce qui va arriver. Quand t’essayes d’effacer un truc et qu’il y a toujours des entrees « filles » tu dois recevoir une erreur, pas automagiquement effacer la moitiee de la base et retourner « 1 record deleted » quand t’en as viré 5000. La meme raison qu’un trigger dans les mains d’un debutant c’est la mal absolu :slight_smile: ou qu’une fonction qui s’appelle DeleteJustThisAndOnlyThis(object o) { o.Child.DeleteAll(); o.Delete(); } c’est tout autant le mal.

Unexpected side effects = LE MAL.

Mais ouai en dev quant t’est tout seul ca peut etre pratique, ou dans des cas bien precis ou c’est clairement attendu.

Tiens tu m’intéresses en parlant des triggers qui t semble plutot mal vu :slight_smile: Vas y explique :crying: Quoique, je doit confondre avec les transaction (et je sais pas pourquoi je pense toute de suite à ca :s)

Deja expliqué :slight_smile: toujours pareil hein:

Du moment que t’utilise un trigger pour faire des trucs qui modifient/font que des trucs qui ont pas de side effects, tant mieux. Maintenant, sans vouloir etre tres tres mheuchant, si tu confonds triggers et transactions va falloir reprendre les bases de la SGBD :crying:

(Une url malefique s’est glissée malencontreusement dans ce message… a force de parter du diable…)

OH MON DIEU !!! Ca y est, mon cerveau se liquefie et du sang me coule des yeux et des oreilles. Salaud, Glop !

Sinon je plussoie joyeusement, les triggers sont vraiment a eviter autant que possible.

Putain, derniere fois que je clique sur un lien de GloP moi…

Merci pour les conseils
C’est à priori résolu :slight_smile: