Forum |  HardWare.fr | News | Articles | PC | Prix | S'identifier | S'inscrire | Shop Recherche
717 connectés 

  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  Requête qui me pose problème

 



 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Requête qui me pose problème

n°2241341
Furaxx
Posté le 27-10-2014 à 17:07:37  profilanswer
 

Bonjour,
 
Je vous expose mon projet et mon problème:
 
Projet:
J'invite des gens à manger, certains n'aiment vraiment pas certains aliments et il faut donc que je prenne ça en compte. De plus, il faut que j'évite de faire 2 fois la même chose aux invités (même si c'est bon ;)).
Je me suis donc fait un petit site web me permettant d'entrer:
- Mes recettes avec des mots-clés qui serviront pour les goûts des personnes
- Les invités avec quelques infos, + des mots-clés décrivant ce qu'ils n'aiment pas (ananas, etc...)
 
Pour gérer ça j'ai plusieurs tables:
- Recettes
CREATE TABLE `recettes` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `titre` varchar(64) NOT NULL,
  `id_type` int(11) NOT NULL,
  `nbPersonnes` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `titre` (`titre`,`id_type`),
  FULLTEXT KEY `titre_2` (`titre`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1
 
- Type (les types de recette: entrée, plats, desserts, etc...)
CREATE TABLE `types` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `type` varchar(32) NOT NULL,
  `ordre` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `ordre` (`ordre`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1
 
- personnes_gouts (qui fait la liaison entre les ID des personnes et les gouts. Si "aime=0" alors c'est quelque chose que la personne n'aime pas)
CREATE TABLE `personnes_gouts` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `id_personne` int(11) NOT NULL,
  `aime` tinyint(4) NOT NULL,
  `gout` varchar(64) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `id_personne` (`id_personne`,`aime`,`gout`),
  KEY `gout` (`gout`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1
 
- personnes_recettes (qui fait la relation entre les ID des personnes et les ID des recettes qu'elles sont déjà eu)
CREATE TABLE `personnes_recettes` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `id_personne` int(11) NOT NULL,
  `id_recette` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `id_personne` (`id_personne`,`id_recette`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1
 
- mots_cles (qui fait la relation entre des ID des recettes et donc les mots-clés qui vont avec)
CREATE TABLE `mots_cles` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `id_recette` int(11) NOT NULL,
  `mot_cle` varchar(32) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `id_recette` (`id_recette`,`mot_cle`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1  
 
 
 
PROBLEME:
Voici ce que je souhaite obtenir:
- Je récupère grâce à un formulaire les ID des personnes qui vont être invitées, et je précise un ID de type (par exemple l'ID 1 qui est le type "entrée" )
- Je voudrais une requête qui me sort un menu que je n'ai pas encore fait aux invités et donc aucun mot-clés desdits recettes ne soient dans les goûts à éviter pour ces mêmes personnes
 
Cette requête sera donc à créer dynamiquement suivant le nombre de personnes cochées, ce que je ferai en PHP, pas de souci là dessus.
 
Par contre voilà, la requête "de base" me pose souci avec après moult essais je n'y parviens pas... Alors qu'il s'agit du principal intérêt du site en question. :D
 
J'espère avoir été clair dans mon explication... A vot' bon cœur m'sieur dames! :)

mood
Publicité
Posté le 27-10-2014 à 17:07:37  profilanswer
 

n°2241349
caps lock
Posté le 27-10-2014 à 17:24:29  profilanswer
 

Je n'ai pas compris où tu étais bloqué :o, tu peux montrer la requête qui te pose problème ?

n°2241445
Furaxx
Posté le 28-10-2014 à 09:26:51  profilanswer
 

Par exemple j'ai pour le moment fait cette requête:
 
SELECT DISTINCT r.id, r.titre, r.nbPersonnes FROM recettes r, mots_cles m WHERE r.id_type=22 AND m.id_recette=r.id AND m.mot_cle NOT IN (SELECT DISTINCT gout FROM personnes_gouts WHERE (id_personne=17 || id_personne=18) AND aime=0)
 
Pour un ID de type=22 et pour 2 personnes d'ID 17 et 18. Ca ne fonctionne évidemment pas. ;)
Je continue à chercher de toute façon mais j'ai "quelques" lacunes en SQL (que je tente de corriger!).

n°2241504
TotalRecal​l
Posté le 28-10-2014 à 11:58:59  profilanswer
 

Un conseil : poste ton schéma sous forme visuelle (un MPD suffira), ça sera plus motivant pour essayer de t'aider :d.
Et les NOT IN et sous requêtes imbriquées c'est mal !


---------------
Réalisation amplis classe D / T      Topic .Net - C# @ Prog
n°2241513
rufo
Pas me confondre avec Lycos!
Posté le 28-10-2014 à 13:37:15  profilanswer
 

Au passage, tu peux avantageusement remplacer (id_personne=17 || id_personne=18) par id_personne In (17, 18) ;)


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Cantine Calandreta : http://sourceforge.net/projects/canteen-calandreta
n°2241515
rufo
Pas me confondre avec Lycos!
Posté le 28-10-2014 à 13:38:46  profilanswer
 

TotalRecall a écrit :

Un conseil : poste ton schéma sous forme visuelle (un MPD suffira), ça sera plus motivant pour essayer de t'aider :d.
Et les NOT IN et sous requêtes imbriquées c'est mal !


Ok pour les NOT IN, par contre, les sous-requêtes, ça dépend : placée dans une Where avec un IN, c'est clair, c'est pas bon pour les perfs. Par contre, une sous-requête dans un FROM, ça peut réduire la taille des les jointures à faire ;)


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Cantine Calandreta : http://sourceforge.net/projects/canteen-calandreta
n°2241520
TotalRecal​l
Posté le 28-10-2014 à 14:02:51  profilanswer
 

Là c'était dans le where [:spamafote].


---------------
Réalisation amplis classe D / T      Topic .Net - C# @ Prog
n°2241544
ddr555
Posté le 28-10-2014 à 15:55:20  profilanswer
 

une requête ne sera jamais satisfaisante. il faut le faire via une procédure stockée

n°2241550
TotalRecal​l
Posté le 28-10-2014 à 16:23:47  profilanswer
 

Et tu mets quoi dans ta procédure stockée à part une requête :??:


---------------
Réalisation amplis classe D / T      Topic .Net - C# @ Prog
n°2241552
rufo
Pas me confondre avec Lycos!
Posté le 28-10-2014 à 16:41:10  profilanswer
 

ddr555 a écrit :

une requête ne sera jamais satisfaisante. il faut le faire via une procédure stockée


Pourquoi donc :??: Et suffisante à quoi ?


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Cantine Calandreta : http://sourceforge.net/projects/canteen-calandreta
mood
Publicité
Posté le 28-10-2014 à 16:41:10  profilanswer
 

n°2241559
MagicBuzz
Posté le 28-10-2014 à 17:16:07  profilanswer
 

Avec CTE (donc pas de MySQL) :

Code :
  1. WITH invites AS
  2. (
  3.     SELECT *
  4.     FROM personne p
  5.     WHERE p.id IN (17, 18)
  6. )
  7. SELECT *
  8. FROM recettes r
  9. WHERE r.id NOT IN (
  10.     SELECT c.id_recette
  11.     FROM invites i
  12.     INNER JOIN personnes_gouts g ON g.id_personne = i.id AND g.aime = 'N'
  13.     INNER JOIN mots_cles_recettes c ON c.mot_cle = g.gout
  14.     union ALL
  15.     SELECT p.id_recette
  16.     FROM invites i
  17.     INNER JOIN personnes_recettes p ON p.id_personne = i.id    
  18. )
  19. AND r.nbPersonnes = (SELECT count(*) FROM invites)
  20. AND r.id_type = 1;
 

Et donc sans CTE, donc MySQL :

Code :
  1. SELECT *
  2. FROM recettes r
  3. WHERE r.id NOT IN (
  4.     SELECT c.id_recette
  5.     FROM personnes p
  6.     INNER JOIN personnes_gouts g ON g.id_personne = p.id AND g.aime = 'N'
  7.     INNER JOIN mots_cles_recettes c ON c.mot_cle = g.gout
  8.        WHERE p.id IN (17, 18)
  9.     union ALL
  10.     SELECT p.id_recette
  11.     FROM personnes_recettes p
  12.        WHERE p.id_personne IN (17, 18)
  13. )
  14. AND r.nbPersonnes = (SELECT count(*) FROM personnes p WHERE p.id IN (17, 18))
  15. AND r.id_type = 1;
 

Je me suis permis de :
- créer une table "mots_cles_recettes" qui fait le lien entre "mots_cles" et "recette"
- changer la signification de "mots_cles" qui se contente d'être les ingrédients potentiellement non désirés (curry, concombre, ananas, etc.)
- plus quelques autres adaptation

 

Code complet de test sous SQL Server pour mieux comprendre :

Code :
  1. -- Jeu de données
  2. WITH recettes AS
  3. (
  4.     SELECT 1 id, 'Poulet au curry' titre, 1 id_type, 2 nbPersonnes
  5.     union ALL
  6.     SELECT 2, 'Lasagnes', 1, 2
  7.     union ALL
  8.     SELECT 3, 'Steak frites', 1, 2
  9.     union ALL
  10.     SELECT 4, 'Tarte au concombre', 2, 2
  11.     union ALL
  12.     SELECT 5, 'Salade de fruits', 2, 8
  13.     union ALL
  14.     SELECT 6, 'Flan au chocolat', 2, 2
  15. ),
  16. types AS
  17. (
  18.     SELECT 1 id, 'Plat principal' type, 2 ordre
  19.     union ALL
  20.     SELECT 2, 'Dessert', 3
  21. ),
  22. personnes_gouts AS
  23. (
  24.     SELECT 1 id, 17 id_personne, 'O' aime, 1 gout
  25.     union ALL
  26.     SELECT 2, 18, 'N', 1
  27.     union ALL
  28.     SELECT 3, 17, 'O', 2
  29.     union ALL
  30.     SELECT 4, 18, 'O', 2
  31.     union ALL
  32.     SELECT 5, 17, 'O', 3
  33.     union ALL
  34.     SELECT 6, 18, 'O', 3
  35.     union ALL
  36.     SELECT 7, 17, 'N', 4
  37.     union ALL
  38.     SELECT 8, 18, 'N', 4
  39.     union ALL
  40.     SELECT 9, 17, 'O', 5
  41.     union ALL
  42.     SELECT 10, 18, 'O', 5
  43. ),
  44. personnes_recettes AS
  45. (
  46.     SELECT 1 id, 17 id_personne, 3 id_recette
  47. ),
  48. mots_cles AS
  49. (
  50.     SELECT 1 id, 'curry' mot_cle
  51.     union ALL
  52.     SELECT 2, 'poulet'
  53.     union ALL
  54.     SELECT 3, 'pâtes'
  55.     union ALL
  56.     SELECT 4, 'concombre'
  57.     union ALL
  58.     SELECT 5, 'ananas'
  59.     union ALL
  60.     SELECT 6, 'steak'
  61.     union ALL
  62.     SELECT 7, 'frittes'
  63. ),
  64. mots_cles_recettes AS
  65. (
  66.     SELECT 1 id, 1 id_recette, 1 mot_cle
  67.     union ALL
  68.     SELECT 1, 1, 2
  69.     union ALL
  70.     SELECT 2, 2, 3
  71.     union ALL
  72.     SELECT 3, 4, 4
  73.     union ALL
  74.     SELECT 4, 6, 5
  75.     union ALL
  76.     SELECT 5, 3, 6
  77.     union ALL
  78.     SELECT 6, 3, 7
  79. ),
  80. personne AS
  81. (
  82.     SELECT 17 id, 'toto' nom
  83.     union ALL
  84.     SELECT 18, 'titi'
  85. ),
  86. -- jeu de données
  87. -- la requête commence ici
  88. invites AS
  89. (
  90.     SELECT *
  91.     FROM personne p
  92.     WHERE p.id IN (17, 18)
  93. )
  94. SELECT *
  95. FROM recettes r
  96. WHERE r.id NOT IN (
  97.     SELECT c.id_recette
  98.     FROM invites i
  99.     INNER JOIN personnes_gouts g ON g.id_personne = i.id AND g.aime = 'N'
  100.     INNER JOIN mots_cles_recettes c ON c.mot_cle = g.gout
  101.     union ALL
  102.     SELECT p.id_recette
  103.     FROM invites i
  104.     INNER JOIN personnes_recettes p ON p.id_personne = i.id    
  105. )
  106. AND r.nbPersonnes = (SELECT count(*) FROM invites)
  107. AND r.id_type = 1;
 

PS :
- Pas de "dinstinct", ça sert à rien (sinon c'est que la requête est fausse) et c'est lent.
- IN sur une PK n'a rien de lent, ça utilise sans problème la clé primaire.
- Les jointures s'écrivent avec le mot clé "JOIN" depuis maintenant 22 ans.


Message édité par MagicBuzz le 28-10-2014 à 17:22:55
n°2241560
lasnoufle
La seule et unique!
Posté le 28-10-2014 à 17:18:53  profilanswer
 

Salut!
 
Je tente le debut, avec IN / NOT IN:

SELECT r.id, r.titre, r.nbPersonnes
FROM recettes r
WHERE r.id NOT IN (
  -- Recettes qu'au moins une personne ne va pas aimer
  SELECT mc.id_recette
  FROM mots_cles mc
  WHERE mot_cle IN (
    -- Gouts qu'au moins une personne n'aime pas
    SELECT pg.gout
    FROM personnes_gouts pg
    WHERE pg.personne_id IN (17,18)
    AND aime = 0
  )
)
AND r.type_id = 22

Et sans IN/NOT IN:

SELECT r.id, r.titre, r.nbPersonnes
FROM recettes r
LEFT JOIN (
  SELECT DISTINCT mc.id_recette
  FROM mots_cles mc
  JOIN (
    SELECT DISTINCT pg.gout
    FROM personnes_gouts pg
    WHERE pg.personne_id IN (17,18)
    AND aime = 0
  ) gouts_a_eviter ON gouts_a_eviter.gout = mc.mot_cle
) recettes_a_eviter ON recettes_a_eviter.id_recette = r.id
WHERE recettes_a_eciter.id_recette IS NULL
AND r.type_id = 22

Et sinon je vois pas trop en quoi ca necessite une procedure stockee.


---------------
C'était vraiment très intéressant.
n°2241566
rufo
Pas me confondre avec Lycos!
Posté le 28-10-2014 à 17:38:54  profilanswer
 

MagicBuzz, ça veut dire quoi CTE :??:


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Cantine Calandreta : http://sourceforge.net/projects/canteen-calandreta
n°2241580
Furaxx
Posté le 28-10-2014 à 19:42:50  profilanswer
 

Bon alors déjà merci à tous pour votre aides et proposition, je vais voir pour tester et continuer ça demain, pas possible de ce soir.
Je ne pensais pas avoir autant de réponses donc ça fait super plaisir déjà, et ça le sera encore plus quand j'aurai vu que ça fonctionne. :p
 
Je vous tiens au jus!

n°2241608
MagicBuzz
Posté le 29-10-2014 à 08:50:24  profilanswer
 

CTE > Common Table Expression
 
C'est un élément de la norme SQL1999.
 
Cela permet de faire des requêtes intermédiaires, qui peuvent être liées entre elles.
 
L'utilisation la plus courante :
- Comme dans mon cas, la création d'un jeu de test, plutôt que de passer par des objets physiques dans la base
- Récursivité
- Refactorisation de sous-select utilisés à plusieurs endroits d'une même requête (comme ça il ne sont évalués qu'une seul fois)
 
MySQL ne supporte évidement pas les CTE.

n°2241622
rufo
Pas me confondre avec Lycos!
Posté le 29-10-2014 à 09:52:43  profilanswer
 

Je ne connaissais pas. Merci pour l'info :jap:


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Cantine Calandreta : http://sourceforge.net/projects/canteen-calandreta
n°2241654
ddr555
Posté le 29-10-2014 à 13:30:26  profilanswer
 

rufo a écrit :


Pourquoi donc :??: Et suffisante à quoi ?


tu n'es jamais assuré d'avoir un résultat à chaque requête.
la meilleure chose c'est de programmer ça en procédure ou dans le code en exécutant chaque requête une par une

n°2241680
MagicBuzz
Posté le 29-10-2014 à 16:44:19  profilanswer
 

Si la requête ramène rien, c'est qu'il n'y a aucun plat à proposer (soit il n'y a que des plats qui ne plaisent pas aux invités, soit les invités ont déjà mangés tous les plats qu'ils aimaient).
 
Dans ce cas, le programme doit prévoir une autre requête pour trouver une recette selon d'autres critères.
 
C'est comme ça qu'il faut faire.
 
Pas faire une procédure qui va faire 25 requêtes (inutile, lourd et difficile à debugger) ni au programme de lancer 25 requêtes avec des curseurs imbriqués ouverts dans tous les sens, ce qui est le meilleur moyen de mettre à genoux le SGBD et l'application cliente.
 
Au contraire, quand on peut répondre à une problématique, aussi complexe soit-être avec une unique requête SQL, aussi complexe soit-elle, il faut impérativement utiliser cette solution.
 
Les procédures stockées et autres algos complexes dans le code client doivent être réservés pour des traitements séquentiels non ensemblistes, pour lesquels le SQL n'est pas correctement armé. Pour le reste, SQL, SQL, SQL, rien d'autre.

n°2241683
ddr555
Posté le 29-10-2014 à 17:18:45  profilanswer
 

je doute que ça soit ce qu'il recherche.
difficile de faire une seule requête qui puisse renvoyer ce qu'il faut
 
et pas d'accord sur ce que tu dis. faut aller au plus efficace. même si tu fais 25 requêtes. ça peut être bien plus efficace qu'une énorme usine à gaz dans une requête.

n°2241684
rufo
Pas me confondre avec Lycos!
Posté le 29-10-2014 à 17:28:00  profilanswer
 

Autant, je suis d'accord avec Magicbuzz sur le fait de ne pas utiliser une procédure stockée autant je rejoins ddr555 sur le fait que dans certains cas, plusieurs requêtes SQL simples peuvent être plus rapides à exécuter qu'une grosse requête SQL complexe.
 
Mais ça dépend pas mal du SGBD, de comment il a été configuré/tuné, de la structure de la BD concernée, des index... Bref, c'est du cas par cas. ;)


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Cantine Calandreta : http://sourceforge.net/projects/canteen-calandreta
n°2241701
Furaxx
Posté le 29-10-2014 à 21:17:02  profilanswer
 

lasnoufle> J'ai essayé tes requêtes qui fonctionnent bien concernant les goûts des personnes, mais qui ne regardent pas les recettes déjà faites.
J'avoue avoir du mal avec les jointures..... :(
 
MagicBuzz> Je vais tester ta solution mais le fait de devoir modifier un peut la structure m'embête un peu car j'ai déjà fait plusieurs choses. :)
 
Quant au fait d'avoir au moins un résultat pour chaque requête ça ne m'était pas venu à l'idée, pour le moment ma priorité est déjà de faire le "filtre" de base. ;)


Message édité par Furaxx le 29-10-2014 à 21:49:40
n°2241703
lasnoufle
La seule et unique!
Posté le 29-10-2014 à 21:54:26  profilanswer
 

ddr555 a écrit :

je doute que ça soit ce qu'il recherche.
difficile de faire une seule requête qui puisse renvoyer ce qu'il faut
 
et pas d'accord sur ce que tu dis. faut aller au plus efficace. même si tu fais 25 requêtes. ça peut être bien plus efficace qu'une énorme usine à gaz dans une requête.


Perso je suis beaucoup plus d'accord avec Magicbuzz. Ce qui est demande ici est largement faisable avec une requete et meme une pas vraiment compliquee (il n'y a qu'a voir les solutions qu'il propose, il faut peut etre les affiner en fonction des retours de Furaxx mais elles sont pas vraiment compliquees).
 
Quant a requete vs code, c'est exactement ce que Magicbuzz dit: ca depend du type de traitement.
 
Maintenant mon experience perso c'est qu'il n'y a pas grand-monde qui sait faire des requetes bien ecrites (comprendre performantes, et j'inclus la declaration d'indexs adequats la-dedans), et pour ceux-la, faire le traitement en code pardonne beaucoup plus.
Mais reste que pour de l'ensembliste, quand tu sais faire (je m'inclus pas forcement dedans), SQL > all


---------------
C'était vraiment très intéressant.
n°2241705
Furaxx
Posté le 29-10-2014 à 22:24:03  profilanswer
 

Je viens de "compléter" ta proposition de requête lasnoufle, ça m'a l'air pas mal comme résultat:
 

Citation :

SELECT r.id, r.titre, r.nbPersonnes  
FROM recettes r  
WHERE r.id NOT IN (  
  -- Recettes qu'au moins une personne ne va pas aimer  
  SELECT mc.id_recette  
  FROM mots_cles mc  
  WHERE mot_cle IN (  
    -- Gouts qu'au moins une personne n'aime pas
    SELECT pg.gout
    FROM personnes_gouts pg
    WHERE pg.id_personne IN (17,18)
    AND aime = 0
  )
)
AND r.id NOT IN (
 SELECT pr.id_recette
 FROM personnes_recettes pr
 WHERE pr.id_personne IN (17,18)
)
AND r.id_type = 22


Je viens de faire plusieurs tests et les résultats obtenus semblent bons.
 
Après, pour gérer le fait où cette requête ne retourne rien, il faudrait peut-être proposer par exemple les 2-3 recettes les plus "vieilles" par exemple, sans se préoccuper de celles déjà réaliser donc.
Ca, rien de compliqué à faire du coup!


Message édité par Furaxx le 29-10-2014 à 22:27:27
n°2241720
ddr555
Posté le 30-10-2014 à 09:25:13  profilanswer
 

le plus gros soucis c'est quand y'a pas de résultat. les jointures externes sont faites pour ça, mais dans ce cas y'a pas d'assurance d'avoir un résultat quelquepart

n°2241725
Oliiii
Posté le 30-10-2014 à 09:55:41  profilanswer
 

Bon, les NOT IN ca m’ennuie :)
Donc j'ai essayé de trouver une query (juste pour le fun) qui n'en utilise pas et au passage qui gère les vielles recettes si aucune ne convient et au final ça donne quelque chose de pas trop compliqué:

Code :
  1. SELECT TOP 3 a.ID, a.titre, MAX(d.DateMangée) DernièreFoisMangée
  2. FROM recettes a
  3.     LEFT JOIN mots_cles b ON b.id_recette = a.ID
  4.     LEFT JOIN personnes_gouts c ON c.aime = 0 AND c.id_personne IN (1, 5) AND c.gout = b.mot_cle
  5.     LEFT JOIN personnes_recettes d ON d.id_personne IN (1, 5) AND d.id_recette = a.ID
  6. WHERE a.id_type = 2
  7. GROUP BY a.ID, a.titre
  8. HAVING MAX(c.ID) IS NULL
  9. ORDER BY Max(d.DateMangée) ASC


 
Evidemment pour gérer les vielles recettes j'ai ajouté un champ a personnes_recettes (DateMangée) pour savoir quand ça a été mangé.
C'est facultatif mais ça me semble être une bonne donnée à avoir.
 
Ya moyen d'encore ajouter des choses facilement, par exemple si il n'y a aucun plats sans ingrédient que les personnes n'aiment pas il est possible de remonter les plats avec le moins de "mauvais" ingrédient en changeant juste le Having MAX(c.ID) is null.

n°2241730
MagicBuzz
Posté le 30-10-2014 à 11:01:59  profilanswer
 

J'ai pas vraiment d'expérience avec MySQL, donc je veux bien croire votre phobie des IN/NOT IN (après tout, avec MySQL, on peut s'attendre à tout).

 

En revanche, IN/NOT IN ne pose aucun problème sur des "vrais" SGBD que sont SQL Server ou Oracle. Et au contraire, ils sont souvent bien plus rapide que les jointures externes, pour la simple et bonne raisons qu'ils permettent de filtrer des sous-ensemble avant de se lancer dans la lecture fastidieuse des autres tables.


Message édité par MagicBuzz le 30-10-2014 à 11:02:24
n°2241733
Furaxx
Posté le 30-10-2014 à 11:09:20  profilanswer
 

Oliiii> Merci, je vais tester ça aussi alors! :)
Je pensais bien ajouter un champs pour gérer le "date mangé" oui.
Je verrai ce que ça donne au niveau temps d'exécution.

n°2241741
ddr555
Posté le 30-10-2014 à 11:41:50  profilanswer
 

mouais, ça dépend de la taille des tables pour les IN sous Oracle.

n°2241765
rufo
Pas me confondre avec Lycos!
Posté le 30-10-2014 à 14:54:22  profilanswer
 

Je dirais que ça dépend des tables concernées et du contenu du IN (si on lui met un grand nb de valeurs dedans)...


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Cantine Calandreta : http://sourceforge.net/projects/canteen-calandreta
n°2241779
Oliiii
Posté le 30-10-2014 à 15:26:36  profilanswer
 

Dans l'absolu ca ne change rien, en général l'optimisateur va pondre le même plan avec ou sans IN.
 
C'est juste que d’expérience la majorité des query que je vois avec IN/NOT IN sont mauvaise alors que celle écrites avec des JOIN sont meilleur (pour SQL Server) probablement du au fait que c'est plus difficile d’écrire un bonne query avec des JOIN donc il faut plus d’expérience et donc on tombe moins dans le panneau.
 
Évidement il y a des exceptions partout :)

mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  Requête qui me pose problème

 

Sujets relatifs
[RESOLU] Postgresql pb d'import fichier CSV avec la commande COPYproblème application sms en vb.net
Problème Ressource/Config/Log4j pas pris en compteProblème code C++ débutant watershed
Problème d'envoi mail en PHP avec easyphp 13.1Probleme encodage JEE/ eclipse / formulaire JSP
Requête d'une donnée dans BDD[RÉSOLU] Problème fenêtre modale et notifications
[Excel 2007] Problème pour trouver le nombre de ligne d'une feuillequotes dans requête pose problème
Plus de sujets relatifs à : Requête qui me pose problème


Copyright © 1997-2018 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR