[Oracle]Mise à jour de clé étrangère aléatoire

Mise à jour de clé étrangère aléatoire [Oracle] - SQL/NoSQL - Programmation

Marsh Posté le 08-07-2010 à 14:40:06    

Bonjour,
 
Je suis sous Oracle, et j'ai un petit problème de "random".
 
Pour faire simple, voici mes tables de travail :

Code :
  1. CREATE TABLE DEPARTEMENT
  2.   (
  3.     "ID"               NUMBER(10,0) NOT NULL ENABLE,
  4.     "NAME"          VARCHAR2(100 CHAR) NOT NULL ENABLE
  5.   )

 

Code :
  1. CREATE TABLE EMPLOYE
  2.   (
  3.     "ID"               NUMBER(10,0) NOT NULL ENABLE,
  4.     "NAME"          VARCHAR2(100 CHAR) NOT NULL ENABLE,
  5.     "DEPT"          NUMBER(10,0)
  6.   )


"DEPT" est une clé étrangère vers la table "DEPARTEMENT".
Je voudrais mettre à jour, de manière aléatoire, ce champ pour tous les employés.
 
Pour tirer une ligne au hasard de la table "DEPARTEMENT", j'utilise :

Code :
  1. SELECT id
  2. FROM
  3.   ( SELECT id FROM DEPARTEMENT ORDER BY dbms_random.value
  4.   )
  5. WHERE rownum = 1;


Ce qui me renvoie bien un id différent à chaque exécution.
Pour la mise à jour de ma clé étrangère, j'utilise :

Code :
  1. UPDATE EMPLOYEE
  2. SET DEPT =
  3.   (SELECT did
  4.   FROM
  5.     (SELECT d.id AS did
  6.     FROM DEPARTEMENT d
  7.     ORDER BY dbms_random.value
  8.     )
  9.   WHERE rownum = 1
  10.   );


Malheureusement, toutes les lignes sont mises à jour avec la même clé, et non pas de manière aléatoire. Apparemment la génération de la clé aléatoire n'est faite qu'une seule fois alors que je voudrais qu'elle le soit pour chaque employé.
Comment faire alors??
 
Merci d'avance pour vos réponses :)

Reply

Marsh Posté le 08-07-2010 à 14:40:06   

Reply

Marsh Posté le 09-07-2010 à 08:10:54    

Je suppose qu'en Oracle, tout comme en SQL server, le random n'est evalué qu'une seule fois par query, donc tu es plus ou moins condamné a faire l'operation row by row dans une boucle.
 
Un moyen pour forcer la fonction random a etre recalculée a chaque fois est de lui donner un seed different (ici tu peux lui filler ton ID) mais la distribution statistique des données ne sera plus vraiment correcte (ca n'a peut etre pas d'importance pour toi).


Message édité par Oliiii le 09-07-2010 à 08:11:21
Reply

Marsh Posté le 09-07-2010 à 08:34:16    

Bon ben j'ai trouvé une autre facon en SQL Server:

Code :
  1. UPDATE #tmpTable
  2.     SET DEPT = ABS(CHECKSUM(NEWID())) % 5


 
NEWID() retourne un GUID, donc ca doit exister sous Oracle
CHECKSUM retourne un INT
ABS pour avoir la valeur absolue
et le % c'est pour faire un modulo pour limiter les valeures (ici entre 0 et 5).
 
Les valeures sont assez bien répartie, meme si c'est pas aussi bon qu'un row by row random.

Reply

Marsh Posté le 11-07-2010 à 18:37:02    

Oliiii a écrit :

et le % c'est pour faire un modulo pour limiter les valeures (ici entre 0 et 5).


Il est communément admis que cette méthode ne donne pas un aléatoire toujours uniformisé.
Il est conseillé, en programmation, de faire plutôt
n=random() * max / RANDMAX
La constante "RANDMAX" étant la valeur maximale que peut renvoyer la fonction random()...


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 12-07-2010 à 16:28:39    

Bonjour et merci pour vos réponses
 
Pour répondre à la question de l'importance de l'aléatoire : peu importe, je veux juste répartir les gens dans les départements pour des besoins de test.
 
Après concernant le bout de code : si je comprends bien, ça retourne un nombre aléatoire entre 0 et n, mais le problème c'est qu'il peut y avoir des "trous" dans les id des départements, et qu'en plus je ne dois utiliser que certains départements (via une condition where).
 
Apparemment la seule solution est de faire une boucle (même si je pensais pas que c'était si compliqué à faire ce genre de choses).
 
Merci encore pour vos réponses :)

Reply

Marsh Posté le 22-07-2010 à 19:03:41    

Bon, avec un peu de retard, je mets une solution que j'ai trouvée pour faire ce que je voulais. Ya surement plus simple, mais comme je m'y connais pas en pl/sql, j'ai pris le premier exemple de boucle que j'ai trouvé :
 

Code :
  1. DECLARE
  2.   CURSOR emp
  3.   IS
  4.     SELECT * FROM EMPLOYE;
  5. BEGIN
  6.   FOR oneEmp IN emp
  7.   LOOP
  8.     UPDATE EMPLOYE emp0
  9.     SET dept =
  10.       (SELECT did
  11.       FROM
  12.         (SELECT d.id AS did FROM DEPARTEMENT d ORDER BY dbms_random.value
  13.         )
  14.       WHERE rownum = 1
  15.       )
  16.     WHERE emp0.id = oneEmp.id;
  17.   END LOOP;
  18. END;
  19. /


 
Si jamais ça peut vous aider :)

Reply

Marsh Posté le 15-08-2010 à 09:30:35    

C'est très bien mais tu n'as pas besoin de ramener toute la table dans ton curseur. SELECT id from EMPLOYE devrait suffire.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed