Précédent   Forum des professionnels en informatique > Bases de données > Oracle > SQL
SQL Forum d'entraide sur le SQL pour Oracle
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 19/05/2011, 14h21   #1
Membre du Club
 
Inscription : décembre 2010
Messages : 190
Détails du profil
Informations forums :
Inscription : décembre 2010
Messages : 190
Points : 60
Points : 60
Par défaut Mettre à jour un Champ

salut à tous,

Je reviens vers vous car j'ai du mal avec une requête!!

J'ai une table qui a plusieurs colonnes dont (NOM_PIECE,FLAG_LIGNE et FLAG_PIECE(initialement à '0') ) et je voudrais mettre à jour FLAG_PIECE dans toute la table comme suit :

En prenant Pièce par pièce : FLAG_PIECE devra être = à MAX(FLAG_LIGNE) après MAJ , mais si toutes les lignes d'une même pièce ont FLAG_LIGNE = '0', ce n'est pas la peine de faire la MAJ puisque FLAG_PIECE est initialement = '0'.

J'ai essayé de le faire avec un curseur :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
curseur IS 
SELECT count(*),NOM_PIECE
FROM TABLE
GROUP BY NOM_PIECE;
 
FOR w_cur IN curseur loop
 
SELECT MAX(FLAG_LIGNE) INTO var
FROM TABLE
WHERE NOM_PIECE = cur.NOM_PIECE;
 
IF var <> '0' then
UPDATE TABLE
SET FLAG_PIECE = var
WHERE STATUS = 'NEW'
AND NOM_PIECE = cur.NOM_PIECE;
end IF;
 
end loop;
Mais ces instructions tournent depuis une heure.

La table fait plus de 5 millions de lignes. et bien sur il y a deux index :

le premier sur (STATUS, NOM_PIECE)
le second sur (NOM_PIECE).
AbouZaid est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/05/2011, 15h04   #2
Membre Expert
 
Inscription : août 2008
Messages : 1 271
Détails du profil
Informations forums :
Inscription : août 2008
Messages : 1 271
Points : 1 929
Points : 1 929
Quelle version d'oracle ? Si 10g+ utilise merge :
Code :
1
2
3
4
5
6
7
8
9
merge INTO TABLE t
USING (SELECT NOM_PIECE, MAX(FLAG_LIGNE) AS max_flag
         FROM TABLE
        WHERE STATUS = 'NEW'
        GROUP BY NOM_PIECE
       HAVING MAX(FLAG_LIGNE) <> '0') u
   ON (t.NOM_PIECE = u.NOM_PIECE)
 when matched then UPDATE
  SET t.FLAG_PIECE = u.max_flag
Sinon il faut utiliser UPDATE mais ce sera moins performant, quelque chose comme ça mais je ne suis pas sûr du HAVING de la clause EXISTS :
Code :
1
2
3
4
5
6
7
UPDATE TABLE t
   SET t.FLAG_PIECE = (SELECT MAX(u.FLAG_LIGNE) FROM TABLE u WHERE u.NOM_PIECE = t.NOM_PIECE AND STATUS = 'NEW')
 WHERE EXISTS (SELECT 1 FROM TABLE u
                WHERE u.NOM_PIECE = t.NOM_PIECE
                  AND STATUS = 'NEW'
                GROUP BY u.NOM_PIECE
               HAVING MAX(u.FLAG_LIGNE) <> '0')
En tout cas, ce qui est sûr, c'est qu'il ne faut pas utiliser de curseur, une seule requête suffit.

[edit]j'avais oublié le when matched then UPDATE...
skuatamad est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/05/2011, 15h07   #3
Modérateur
 
Homme Fabien
Ingénieur d'études en décisionnel
Inscription : septembre 2008
Messages : 5 684
Détails du profil
Informations personnelles :
Nom : Homme Fabien
Âge : 34
Localisation : France, Yvelines (Île de France)

Informations professionnelles :
Activité : Ingénieur d'études en décisionnel
Secteur : Arts - Culture

Informations forums :
Inscription : septembre 2008
Messages : 5 684
Points : 10 433
Points : 10 433
Envoyer un message via ICQ à Waldar Envoyer un message via Skype™ à Waldar
Évidemment que c'est lent, vous avez un premier curseur pour récupérer vos noms de pièce, puis une requête appelée à chaque ligne pour récupérer le max, et enfin la mise à jour qui tombe.

SQL est un langage ensembliste.
Il faut que vous le compreniez sinon vous n'aurez jamais de bonnes performances.

Tout votre bloc s'écrit ainsi :
Code :
1
2
3
4
5
6
7
8
9
merge INTO matable mt1
USING (  SELECT nom_piece, max(flag_ligne) AS flag_piece
           FROM matable
       GROUP BY nom_piece
         HAVING max(flag_ligne) <> '0') mt2
   ON (mt1.nom_piece = mt2.nom_piece)
 when matched then UPDATE
  SET mt1.flag_piece = mt2.flag_piece
WHERE mt1.STATUS = 'NEW';
__________________
Email : http://scr.im/waldar
Waldar est déconnecté   Envoyer un message privé Réponse avec citation 20
Vieux 19/05/2011, 15h42   #4
Membre Expert
 
Inscription : août 2008
Messages : 1 271
Détails du profil
Informations forums :
Inscription : août 2008
Messages : 1 271
Points : 1 929
Points : 1 929
Au fait Waldar a raison, le WHERE mt1.STATUS = 'NEW' doit être placé après le SET pour correspondre à ton process initial et pas dans la requête USING
skuatamad est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/05/2011, 17h25   #5
Membre du Club
 
Inscription : décembre 2010
Messages : 190
Détails du profil
Informations forums :
Inscription : décembre 2010
Messages : 190
Points : 60
Points : 60
Merciiiiiiii, je vais l'essayer de suite!!!
AbouZaid est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/05/2011, 17h39   #6
Membre du Club
 
Inscription : décembre 2010
Messages : 190
Détails du profil
Informations forums :
Inscription : décembre 2010
Messages : 190
Points : 60
Points : 60
j'ai essayé de comprendre l'instruction Merge , mais je n'y arrive pas.

Qlq aurait la gentillesse de me donner un exemple bien clair?

merci
AbouZaid est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 19h43.


 
 
 
 
Partenaires

Hébergement Web