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'
4 réponses
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
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
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
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.
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.
De nouvelles questions
mysql
MySQL est un système de gestion de base de données relationnelle (RDBMS) gratuit et open source qui utilise SQL (Structured Query Language). N'UTILISEZ PAS cette balise pour d'autres bases de données telles que SQL Server, SQLite, etc. Ce sont des bases de données différentes qui utilisent toutes leurs propres dialectes SQL pour gérer les données.