Select + rand unique

Select + rand unique - SQL/NoSQL - Programmation

Marsh Posté le 03-03-2013 à 23:00:20    

Bonsoir, j'ai un problème sur lequel je bloque, je vous explique rapidement avant de vous décrire les tables.
 
Je dois sélectionner aléatoirement dans une table un nombre X de lignes (2 pour l'exemple), ces lignes doivent avoir un GROUPE_ID différent d'un de celui présent dans une autre table et doivent être différents entre eux lors de la sélection. Le tout doit être inséré dans une nouvelle table. Voici le détail des tables.
 
TABLE NOMS
ID(ai) | NOM
    1_____A
    2_____B
    3_____C
 
TABLE MERE
ID(ai) | GROUPE_ID | IDENTIFIANT | CONTENU
1__________1___________01________xxx
2__________1___________02________xxx
3__________2___________01________yyy
4__________3___________03________zzz
5__________4___________04________aaa
6__________2___________03________yyy
 
TABLE fille1
NOM | GROUPE_ID
  A ______ 1      
  A ______ 4
  B ______ 1
  B ______ 2
  C ______ 3
  C ______ 4
 
TABLE fille2 (la ou l'insertion se fait)
NOM | GROUPE_ID
 
 -------------------------------------------------------------
 
En fait je sélectionne un NOM (ici A), je dois prendre 2 lignes de la TABLE MERE dont les GROUPE_ID sont différents entre eux et son aussi différents de ceux de la TABLE fille1 qui correspondent a ce NOM. Et je dois les insérer dans la table fille 2.
Concrètement dans l'exemple, A devrait avoir 2 lignes dans la TABLE fille2, 2 et 3 ou 3 et 2 peut importe l'ordre.  
 
Je n'arrive pas a faire cette sélection particulière, quelqu'un saurait-il comment procéder s'il vous plait ?  
 
Merci d'avance.

Reply

Marsh Posté le 03-03-2013 à 23:00:20   

Reply

Marsh Posté le 04-03-2013 à 02:02:37    

Bonsoir,
 
Je ne suis pas sur d'avoir bien compris la demande... Comment sont liées les tables entre elles ?
 
J'ai codé rapidement le schéma de cette partie de bdd, peux-tu rajouter les liaisons de tables ?
 

Code :
  1. CREATE TABLE MERE (
  2. ID INT,
  3. GROUPE_ID INT,
  4. IDENTIFIANT INT,
  5. CONTENU VARCHAR(100)
  6. );
  7. CREATE TABLE NOMS (
  8. ID INT,
  9. NOM VARCHAR(100)
  10. );
  11. CREATE TABLE fille1 (
  12. NOM VARCHAR(100),
  13. GROUPE_ID INT
  14. );
  15. CREATE TABLE fille2 (
  16. NOM VARCHAR(100),
  17. GROUPE_ID INT
  18. );


 
J'ai aussi fait un jeu de test rapide, mais comme je ne sais pas comment sont liées les tables je ne suis pas sûr d'avoir bien deviné ^^
 

Code :
  1. INSERT INTO MERE (ID, GROUPE_ID, IDENTIFIANT, CONTENU)
  2. VALUES (1, 1, 1, "NOM_01" ),
  3.  (2, 2, 2, "NOM_02" ),
  4.  (3, 3, 3, "NOM_03" ),
  5.  (4, 4, 4, "NOM_04" ),
  6.  (5, 5, 5, "NOM_05" ),
  7.  (6, 6, 6, "NOM_06" );
  8. INSERT INTO NOMS (ID, NOM)
  9. VALUES (1, "NOM_01" ),
  10.  (2, "NOM_02" ),
  11.  (3, "NOM_03" ),
  12.  (4, "NOM_04" ),
  13.  (5, "NOM_05" ),
  14.  (6, "NOM_06" );
  15. INSERT INTO fille1 (NOM, GROUPE_ID)
  16. VALUES ("NOM_01", 1), ("NOM_01", 10),
  17.  ("NOM_02", 2), ("NOM_02", 20),
  18.  ("NOM_03", 3), ("NOM_03", 30),
  19.  ("NOM_04", 4), ("NOM_04", 40),
  20.  ("NOM_05", 5), ("NOM_05", 50),
  21.  ("NOM_06", 6), ("NOM_06", 60);


 
Et du coup la requête simplifiée de ce que tu demandes (pas de résultat aléatoire, et pas de distinction sur le GROUPE_ID de la table MERE)

Code :
  1. SELECT  `MERE`.`CONTENU` ,  `MERE`.`GROUPE_ID`
  2. FROM  `MERE` ,  `fille1`
  3. WHERE  `MERE`.`CONTENU` =  `fille1`.`NOM`
  4. AND  `MERE`.`GROUPE_ID` !=  `fille1`.`GROUPE_ID`
  5. LIMIT 2;


 
Alors dis moi si j'ai bien compris ta demande et je te ferai la requete ^^
 
Je pense aussi, c'est un problème de passer par une fonction ? Ta BDD est sous Mysql ?

Reply

Marsh Posté le 04-03-2013 à 19:47:09    

Bonsoir et merci pour ta réponse, je n'ai pas encore eu le temps de tester ta requête mais je vais t'éclairer sur certains points car j'ai oublier une chose hier.  
Sinon je suis sous MySQL et toute proposition est la bienvenue, fonction, etc...
 
On a plusieurs pseudos dans la table NOM qui vont donner une appréciation sur un produit (suivant différents critères extérieurs et et non utile ici), je fais donc une premiere requete qui va me chercher les pseudos et qui pour chacun d'eux doit faire le boulot demandé dans le 1er post.
Il y a 4 fournisseurs (IDENTIFIANT dans la table MERE), et environ 30 types de produits (GROUP_ID).
On a également une variable appelé ici $genre qui détermine le nombre de produit que doit recevoir chaque pseudo chaque jour. (soit 4 soit 8 soit 12)
 
Le but est que chaque pseudo reçoive chaque jour un nombre de produit defini par $genre, et qui soit :
1 - soit 1 produit par IDENTIFIANT, soit 2 produits par IDENTIFIANT, soit 3 produits par IDENTIFIANT
2 - Différent des produits qu'ils a eu la veille
3 - Différents entre eux.
 
Les liaisons entre TABLE NOMS, TABLE fille1 et TABLE fille2 sont les NOM.
Pour la TABLE MERE il n'y a pas de lien car c'est là qu'on doit aller chercher les produits au hasard mais sans doublons dans la sélection du jour et sans doublon par rapport a la veille.
Par doublon je parle de GROUP_ID, même si c'est pas le même fournisseur c'est le même produit donc il a le même GROUP_ID
 
Ensuite chaque jours a 0h00, une cron vient vider la table fille1, copie la table fille2 dans fille1, vide la table fille2 et fait une nouvelle selection qu'il insert dans la table fille2.
 
j'espère avoir été plus précis dans l'execution du système :)
 
Merci.


Message édité par lipps le 04-03-2013 à 19:49:59
Reply

Marsh Posté le 05-03-2013 à 01:28:19    

je poste les structures exactes :
 

Code :
  1. CREATE TABLE IF NOT EXISTS `test_mere` (
  2.   `id` int(10) NOT NULL AUTO_INCREMENT,
  3.   `group_id` int(10) NOT NULL,
  4.   `proprio` varchar(20) NOT NULL,
  5.   `contenu` varchar(200) NOT NULL,
  6.   PRIMARY KEY (`id`)
  7. ) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=21 ;
  8. --
  9. -- Contenu de la table `test_mere`
  10. --
  11. INSERT INTO `test_mere` (`id`, `group_id`, `proprio`, `contenu`) VALUES
  12. (1, 1, 'fournisseur1', 'a'),
  13. (2, 2, 'fournisseur2', 'b'),
  14. (3, 2, 'fournisseur1', 'b'),
  15. (4, 1, 'fournisseur3', 'a'),
  16. (5, 3, 'fournisseur3', 'c'),
  17. (6, 4, 'fournisseur1', 'd'),
  18. (7, 3, 'fournisseur4', 'c'),
  19. (8, 2, 'fournisseur4', 'b'),
  20. (9, 2, 'fournisseur3', 'b'),
  21. (10, 3, 'fournisseur2', 'c'),
  22. (11, 5, 'fournisseur1', 'd'),
  23. (12, 6, 'fournisseur2', 'e'),
  24. (13, 6, 'fournisseur1', 'e'),
  25. (14, 5, 'fournisseur3', 'd'),
  26. (15, 7, 'fournisseur3', 'f'),
  27. (16, 8, 'fournisseur1', 'g'),
  28. (17, 7, 'fournisseur4', 'f'),
  29. (18, 6, 'fournisseur4', 'e'),
  30. (19, 6, 'fournisseur3', 'e'),
  31. (20, 7, 'fournisseur2', 'f');


 
 

Code :
  1. CREATE TABLE IF NOT EXISTS `test_fille1` (
  2.   `pseudo` varchar(200) NOT NULL,
  3.   `id_jeu` int(10) NOT NULL,
  4.   `group_id` int(10) NOT NULL
  5. ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
  6. --
  7. -- Contenu de la table `test_fille1`
  8. --
  9. INSERT INTO `test_fille1` (`pseudo`, `id_produit`, `group_id`) VALUES
  10. ('user1', 1, 1),
  11. ('user1', 2, 2),
  12. ('user1', 5, 3),
  13. ('user1', 17, 7);


 

Code :
  1. CREATE TABLE IF NOT EXISTS `test_fille2` (
  2.   `pseudo` varchar(200) NOT NULL,
  3.   `id_produit` int(10) NOT NULL,
  4.   `group_id` int(10) NOT NULL
  5. ) ENGINE=MyISAM DEFAULT CHARSET=latin1;


 
on part sur l'exemple pour l'user1 soit 4 type de produits a tester (1 de chaque éditeur)
l'user1 a eu hier 4 catégories de produits différentes dont 1 de chaque éditeur.
Il faut que pour aujourd'hui, on lui attribue 1 catégorie de chaque fournisseur (donc 4 en tout), différentes de la veille et différentes entre elles. C'est le GROUP_ID qui doit differer.
et donc dans la table `test_fille2` on doit avoir 4 lignes du style : 'user1' - 'id (de la table mere)' - 'group_id'
 
je pense que ça ira mieux avec les infos exactes.
Merci.


Message édité par lipps le 05-03-2013 à 01:53:56
Reply

Marsh Posté le 05-03-2013 à 09:59:14    

Je suis pas sûr d'avoir compris ce que tu veux. Mais tu peux tenter ça:
 

Code :
  1. SELECT 'user1',id,group_id
  2. FROM test_mere
  3. WHERE group_id
  4.   NOT IN(SELECT group_id FROM test_fille1 WHERE pseudo = 'user1') -- différents de la veille
  5. GROUP BY GROUP_ID -- différents entre eux
  6. ORDER BY RAND() LIMIT 0,4 -- nombre de groupes

Reply

Marsh Posté le 05-03-2013 à 22:07:54    

Bonsoir, merci pour votre requête qui s'approche de ce que je souhaite, mais il reste un problème.
 
J'ai utilisé votre requete de cette façon : $user = 'user1';

Code :
  1. SELECT proprio,id,group_id
  2.     FROM test_mere
  3.     WHERE group_id
  4.       NOT IN(SELECT group_id FROM test_fille1 WHERE pseudo = '$user')
  5.     GROUP BY GROUP_ID
  6.     ORDER BY RAND() LIMIT 0,4


 
et en fait on a jamais 2 GROUP_ID identique entre eux, ni identique a un de la veille, mais par contre il me sort des fournisseurs identiques hors il me faut pour 4 GROUP_ID => 4 Fournisseurs differents. pour 8 GROUP_ID, 2 de chaque fournisseur et pour 12 GROUP_ID, 3 de chaque fournisseur.
 
Voici 1 exemple de ce qu'il me sort : (ici 2 fois le fournisseur 3)
GROUP_ID : 7 - FOURNISSEUR : editeur4 - ID : 17
GROUP_ID : 12 - FOURNISSEUR : editeur1 - ID : 23
GROUP_ID : 10 - FOURNISSEUR : editeur3 - ID : 21
GROUP_ID : 6 - FOURNISSEUR : editeur3 - ID : 19  
 
ou encore  ici 2 fois le fournisseur 1
GROUP_ID : 11 - FOURNISSEUR : editeur4 - ID : 22
GROUP_ID : 12 - FOURNISSEUR : editeur1 - ID : 23
GROUP_ID : 10 - FOURNISSEUR : editeur3 - ID : 21
GROUP_ID : 5 - FOURNISSEUR : editeur1 - ID : 11  
 
Merci.

Reply

Marsh Posté le 05-03-2013 à 23:52:29    

Bon finalement j'ai codé un truc un peu a l'arrache qui envoit ligne par ligne dans la table test_fille2 en vérifiant de ne pas faire de doublons, c'est un peu laid mais j'ai pas trouvé d'autre solution.
Je poste ce que ça donne si ça peut aider quelqu'un.
 

Code :
  1. $user = 'user1'; // ici on a besoin que d'1 seul user pour faire le test
  2. $proprio1 = 'editeur1';
  3. $proprio2 = 'editeur2';
  4. $proprio3 = 'editeur3';
  5. $proprio4 = 'editeur4';
  6. $groupe = 2; // besoin que de 4 GROUP_ID ici
  7. if ($groupe == 2) {$type = 1;} // GENERE 4 GROUP_ID
  8. if ($groupe == 3) {$type = 2;} // GENERE 8 GROUP_ID
  9. if ($groupe == 1 || $groupe == 4) {$type = 3;} // GENERE 12 GROUP_ID
  10. function generer($user, $proprio) {
  11.     $infos=mysql_query("SELECT proprio,id,group_id
  12.     FROM test_mere
  13.     WHERE group_id
  14.       NOT IN(SELECT group_id FROM test_fille1 WHERE pseudo = '$user')
  15.   AND proprio='$proprio'
  16.   AND group_id NOT IN(SELECT group_id FROM test_fille2 WHERE pseudo = '$user')
  17.     ORDER BY RAND() LIMIT 0,1 " ) or die ('Erreur : '.mysql_error());
  18. while ($resultat = mysql_fetch_array($infos) ){
  19. $group_id = $resultat['group_id'];
  20. $id = $resultat['id'];
  21. $proprio = $resultat['proprio'];
  22. return array( $group_id, $proprio, $id );
  23. }
  24. }
  25. for ($n = 1; $n <= $type; $n++) {
  26. for ($i = 1; $i <= 4; $i++) {
  27. if ($i == 1) {$retour = generer($user, $proprio1);}
  28. if ($i == 2) {$retour = generer($user, $proprio2);}
  29. if ($i == 3) {$retour = generer($user, $proprio3);}
  30. if ($i == 4) {$retour = generer($user, $proprio4);}
  31.    
  32. $ajout1 = mysql_query("INSERT INTO test_fille2 VALUES ('$user', '$retour[2]', '$retour[0]')" )  or die ('Erreur : '.mysql_error());
  33. //echo "$retour[0] - $retour[1] - $retour[2] <br />";
  34. }
  35. }


 
Si vous avez une solution plus propre je suis preneur ^^

Reply

Sujets relatifs:

Leave a Replay

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