J'ai trois tables patients, qui contient le nom de mes patients, Contrôles qui représente les contrôles d'interface utilisateur pouvant être tirés pour chaque maladie et ControlsValues = Table contenant les valeurs des commandes soumises pour chaque patient
Permet de disposer de certaines données patients Table
|ID | Name |
|-----------|
| 1 | Ara |
| 2 | Sada |
Contrôles Tableau
|ID | Text | Type |
|-----------|----------|
| 1 | age | textbox |
| 2 |alergy| checkbox |
Alors le contrôlevalues table qui est là où je veux interroger à
|ID | contrlId | value | patientId |
|---------------|----------|-----------|
| 1 | 1 | 23 | 1 |
| 2 | 2 | true | 1 |
| 3 | 1 | 26 | 2 |
| 4 | 2 | false | 2 |
ici, mon problème se produit lorsque je veux retourner ce patient de ControlsValues
table qui a le (controlId=1
ET value=23
) et (controlId=2
ET value=true
) Dans ce cas, la condition est sur deux rangées et non deux colonnes que ce n'est pas possible, je déséquilibre de modifier les lignes dans les colonnes en fonction de controlId
mais je ne sais pas comment et je suis à la recherche de la recherche. 2 jours et vu beaucoup d'échantillons mais aucun d'entre eux m'a aidé à résoudre mon problème
Vous pouvez essayer ce genre de "solution":
http://sqlfiddle.com/#!9/d33a95/18
Ce n'est pas une solution "pivot-table", mais peut-être que cela résout votre problème - si je l'ai bien compris.
Voici les tables/données utilisées:
CREATE TABLE `patients` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR( 50 ) NOT NULL ,
PRIMARY KEY ( `ID` )
);
CREATE TABLE `controls` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Text` VARCHAR( 50 ) NOT NULL ,
`Type` VARCHAR( 50 ) NOT NULL ,
PRIMARY KEY ( `ID` )
);
CREATE TABLE `controlvalues` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`ControlID` INT NOT NULL ,
`Value` VARCHAR( 50 ) NOT NULL ,
`PatientID` INT NOT NULL ,
PRIMARY KEY ( `ID` )
);
INSERT INTO `patients` (`Name`) VALUES ('Ara'), ('Sada'), ('Pada'), ('Lada');
INSERT INTO `controls` (`Text`, `Type`) VALUES ('age', 'textbox'), ('alergy', 'checkbox');
INSERT INTO `controlvalues` (`ControlID`, `Value`, `PatientID`) VALUES
(1, '23', 1),
(2, 'true', 1),
(1, '25', 2),
(2, 'false', 2),
(1, '23', 3),
(2, 'false', 3),
(1, '23', 4),
(2, 'true', 4);
Et la requête:
SELECT PatientID, COUNT(PatientID) AS PatCount, p.Name
FROM controlvalues cv
LEFT JOIN patients p ON p.ID = cv.PatientID
WHERE ((ControlID = 1 AND Value = '23')
OR (ControlID = 2 AND Value = 'true'))
GROUP BY PatientID
HAVING PatCount = 2
;
Vous pouvez obtenir votre réponse sans avoir besoin de pivoter vos données. L'approche la plus directe (de mon point de vue) utilise EXISTS
, qui reflète très directement votre déclaration:
SELECT
p.ID, p.Name
FROM
patients p
WHERE
EXISTS
(
SELECT 1
FROM controlvalues cv1
WHERE p.ID = cv1.PatientID
AND cv1.controlId = 1
AND cv1.value = '23'
)
AND
EXISTS
(
SELECT 1
FROM controlvalues cv2
WHERE p.ID = cv2.PatientID
AND cv2.controlId = 2
AND cv2.value = 'true'
) ;
Qui va juste revenir:
[.____] id | Nom [.____] -: | : --- 1 | Ara
Comme alternative, vous pouvez modifier le EXISTS
à JOIN
s:
SELECT
p.ID, p.Name
FROM
patients p
JOIN controlvalues cv1
ON cv1.PatientID = p.ID AND cv1.controlId = 1 AND cv1.value = '23'
JOIN controlvalues cv2
ON cv2.PatientID = p.ID AND cv2.controlId = 2 AND cv2.value = 'true' ;
qui retournera les mêmes résultats. La requête est plus concise, mais, à mon avis, un peu plus difficile à lire.
Les plans d'exécution (à partir de Mariambb 10.2) sont les mêmes, à condition que les bons indices (ou, dans mon cas, la clé primaire) ont été définis.
Si vous voulez vraiment pivoter vos données, c'est comme ça que vous le feriez:
SELECT
p.ID, p.Name,
max(case when controlId = 1 then value end) AS controlId1 /* age */,
max(case when controlId = 2 then value end) AS controlId2 /* allergy */
FROM
patients p
JOIN controlvalues cv ON cv.PatientId = p.ID
GROUP BY
p.ID ;
C'est la table pivotée:
[.____] id | Nom | contrôlé1 | contrôlé2 -: | : : ---------- | : ---------- [.____] 1 | Ara | 23 | vrai 2 | Sada | 25 | faux
... Et c'est comme ça que vous l'utiliseriez:
SELECT
pp.ID, pp.Name
FROM
(
SELECT
p.ID, p.Name,
max(case when controlId = 1 then value end) AS controlId1,
max(case when controlId = 2 then value end) AS controlId2
FROM
patients p
JOIN controlvalues cv ON cv.PatientId = p.ID
GROUP BY
p.ID
) AS pp
WHERE
pp.controlId1 = '23' AND pp.controlId2 = 'true';
[.____] id | Nom [.____] -: | : --- 1 | Ara
Le plan d'exécution pour le pivoté Tableau, cependant, pourrait probablement être pire (spécialement dans une grande table).
Vous pouvez tout vérifier en dbfiddle --- (ICI