Je souhaite sélectionner un ID utilisateur dans une seule table en fonction de plusieurs et d'une condition.

UserID   FieldID  Value
-----------------------------------
1        51         Yes 
1        6          Dog 
2        6          Cat
1        68         TX  
1        69         78701
2        68         LA     

Ce que j'essaie d'obtenir en termes simples:

Si l'utilisateur recherche texas ou 78701, sélectionnez userId où (68 = TX OR 69 = 78701) AND (51 = yes) AND (6 = Dog)

Cela devrait renvoyer l'ID utilisateur 1.

C'est ce que j'ai essayé, mais renvoie null.

SELECT user_id FROM `metadata` 
WHERE ( (`field_id` = '68' AND value LIKE '%TX%') 
   OR (`field_id` = '69' AND value LIKE '%78701%') ) 
   AND `field_id` = '51' AND value = 'Yes'
   AND `field_id` = '6' AND value = 'Dog'
1
Jimmy 16 nov. 2017 à 13:03

4 réponses

Meilleure réponse

Vous pouvez utiliser GROUP BY avec une clause HAVING qui utilise plusieurs agrégats conditionnels :

SELECT UserID
FROM metadata
GROUP BY UserID
HAVING SUM(field_id = '68' AND value LIKE '%TX%' OR
           field_id = '69' AND value LIKE '%78701%') >= 1

       AND

       SUM(field_id = '51' AND value = 'Yes') >= 1

       AND

       SUM(field_id = '6' AND value = 'Dog') >= 1

Démo ici

Explication: Dans MysQL, une expression booléenne, comme

field_id = '51' AND value = 'Yes'

Renvoie 1 quand vrai, 0 quand faux.

De plus, chaque prédicat de la clause HAVING est appliqué au groupe entier d'enregistrements, tel que défini par GROUP BY.

Par conséquent, prédicat:

SUM(field_id = '51' AND value = 'Yes') >= 1

Revient à dire: ne renvoie que les groupes UserID ayant au moins un (> = 1) enregistrement avec

field_id = '51' AND value = 'Yes' -> true
3
Giorgos Betsos 16 nov. 2017 à 10:18

SELECT user_id FROM metadata OÙ (field_id = '68' AND valeur LIKE '% TX%') OR (field_id = '69' AND valeur LIKE '% 78701%') AND (field_id = '51' AND value = 'Yes') AND (field_id = '6' AND value = 'Dog');

J'ai un peu changé votre requête et essayé avec le même, il donne la sortie comme, user_id est 1

0
Ponni 16 nov. 2017 à 10:40

Cette approche est généralement plus lente que de simplement joindre à gauche cette table sur chaque critère, mais elle peut rendre le problème plus simple à comprendre ...

SELECT userid
     , MAX(CASE WHEN fieldid = 51 THEN value END) smoker
     , MAX(CASE WHEN fieldid =  6 THEN value END) favourite_pet
     , MAX(CASE WHEN fieldid = 68 THEN value END) state
     , MAX(CASE WHEN fieldid = 69 THEN value END) zip
  FROM eav
 GROUP
    BY userid;

Vous pouvez utiliser HAVING ou regrouper ceci dans une sous-requête pour obtenir les résultats souhaités.

0
Strawberry 16 nov. 2017 à 10:23

La structure de votre table ressemble à la modélisation attribut + valeur, qui divise essentiellement les colonnes d'une ligne en paires individuelles et a pour effet secondaire un typage très faible.

Comme vous l'avez noté, cela peut également rendre les requêtes difficiles, car vous devez raisonner sur plusieurs lignes pour donner un sens au modèle de données d'origine.

Une approche pourrait être de prendre une opinion sur un critère `` principal '', puis d'appliquer des critères supplémentaires en raisonnant sur les données déchiquetées, jointes par l'identifiant de l'utilisateur:

SELECT DISTINCT m.user_id 
FROM `metadata` m
WHERE ((`field_id` = '68' AND value LIKE '%TX%') 
       OR (`field_id` = '69' AND value LIKE '%78701%'))
 AND EXISTS 
 (SELECT 1 
    FROM `metadata` m2 
    WHERE m2.user_id = m.user_id AND m2.field_id = '51' AND m2.value = 'Yes')
AND EXISTS 
  (SELECT 1 
     FROM `metadata` m3 
     WHERE m3.user_id = m.user_id AND m3.field_id = '6' AND m3.value = 'Dog');

Cependant, l'OMI, il peut être préférable d'essayer de remodeler le tableau comme tel (et idéalement de choisir de meilleures descriptions pour les attributs sous forme de colonnes):

UserID   Field51  Field6 Field68  Field69
----------------------------------------
1        Yes      Dog     TX      78701
2        No       Cat     LA      NULL

Cela rendra les choses beaucoup plus faciles à interroger.

0
StuartLC 16 nov. 2017 à 10:22
47326707