Aider à construire une requête SQL à partir de plusieurs tables
Question
Compte tenu des tableaux ci-dessous, comment pourrais-je construire une requête SQL qui contient une liste de tous les éléments de la table « éléments », et une colonne pour chaque couleur de la table « couleurs » qui, pour chaque élément répertorié, indique quelles couleurs l'élément a une relation avec.
Si ce n'est pas clair du tout, s'il vous plaît laissez-moi savoir quelles informations supplémentaires aideront à clarifier. Les informations de la table et le résultat SQL souhaitées sont ci-dessous:
table des éléments:
id | item_name
1 | 'item 1'
2 | 'item 2'
3 | 'item 3'
table couleurs:
id | color_name
1 | 'red'
2 | 'blue'
3 | 'green'
table item_color:
item_id | color_id
1 | 1
1 | 3
2 | 2
2 | 3
3 | 2
souhaité résultat de la requête SQL:
item_name | red | blue | green
'item 1' | 1 | null | 1
'item 2' | null| 1 | 1
'item 3' | null| 1 | null
Merci, Colin
La solution
Utilisation:
SELECT item_name,
MAX(red) 'red',
MAX(blue) 'blue',
MAX(green) 'green'
FROM (SELECT t.item_name,
CASE
WHEN c.color_name = 'red' THEN
1
ELSE
NULL
END 'red',
CASE
WHEN c.color_name = 'blue' THEN
1
ELSE
NULL
END 'blue',
CASE
WHEN c.color_name = 'green' THEN
1
ELSE
NULL
END 'green'
FROM ITEMS t
JOIN ITEM_COLOR ic ON ic.item_id = t.item_id
JOIN COLORS c ON c.id = ic.color_id)
GROUP BY item_name
Modifier MAX COUNT si vous voulez que le # total de rouge / bleu / vert associé à un élément.
Autre à l'aide des sous-requêtes Affacturage:
WITH icolors AS (
SELECT t.item_name,
CASE
WHEN c.color_name = 'red' THEN
1
ELSE
NULL
END 'red',
CASE
WHEN c.color_name = 'blue' THEN
1
ELSE
NULL
END 'blue',
CASE
WHEN c.color_name = 'green' THEN
1
ELSE
NULL
END 'green'
FROM ITEMS t
JOIN ITEM_COLOR ic ON ic.item_id = t.item_id
JOIN COLORS c ON c.id = ic.color_id)
SELECT t.item_name,
MAX(t.red) 'red',
MAX(t.blue) 'blue',
MAX(t.green) 'green'
FROM icolors t
GROUP BY t.item_name
Autres conseils
Êtes-vous sur 11g oracle?
Cela semble être une utilisation idéale pour le nouveau la fonction de pivot dans 11g
Si vous connaissez toutes les couleurs possibles à l'avance, vous pouvez le faire, mais messily efficacement. Si vous ne connaissez pas toutes les couleurs possibles à l'avance, il est très difficile - vous devez exécuter certaines requêtes pour savoir quelles colonnes apparaissent dans le tableau de résultats, puis élaborer le SQL pour créer ces colonnes (SQL dynamique) .
Alors, supposons que vous connaissez les colonnes du tableau de résultat:
SELECT i.item_name, r.red, b.blue, g.green
FROM items i
LEFT JOIN
(SELECT item_name, COUNT(*) AS red
FROM item_color
WHERE color_id = 1
GROUP BY item_name) AS r
ON i.item_name = r.item_name
LEFT JOIN
(SELECT item_name, COUNT(*) AS green
FROM item_color
WHERE color_id = 3
GROUP BY item_name) AS g
ON i.item_name = g.item_name
LEFT JOIN
(SELECT item_name, COUNT(*) AS blue
FROM item_color
WHERE color_id = 2
GROUP BY item_name) AS b
ON i.item_name = b.item_name
Notez que dans cette formulation, je l'ai utilisé les données des couleurs Tableau dans la construction de la requête. Et autre forme construirait les sous-requêtes que (interne) se joint à la table des couleurs, en utilisant le nom de couleur au lieu du code dans les clauses WHERE.
create table item (id number not null, item_name varchar2(200) not null);
create table color (id number not null, color_name varchar2(200) not null);
create table item_color (item_id number not null, color_id number not null);
insert into item values (1, 'item 1');
insert into item values (2, 'item 2');
insert into item values (3, 'item 3');
insert into color values (1, 'red');
insert into color values (2, 'blue');
insert into color values (3, 'green');
insert into item_color values (1, 1);
insert into item_color values (1, 3);
insert into item_color values (2, 2);
insert into item_color values (2, 3);
insert into item_color values (3, 2);
commit;
puis sélectionnez:
select * from
(
select
i.item_name
, c.color_name
from
item i
, color c
, item_color ic
where
ic.item_id = i.id
and ic.color_id = c.id
) pivot (
count(color_name) cnt
for color_name in ('red', 'blue', 'green')
);
donne:
item 1 1 0 1
item 2 0 1 1
item 3 0 1 0
Si vous ne connaissez pas la liste des couleurs à l'avance, vous pouvez sélectionner la table de couleurs d'abord, puis construire le pivot sélectionner dynamiquement (un sous-sélection comme for color_name in (select color_name from color)
n'est pas possible) ou bien vous pouvez utiliser pivot xml
et post-traiter le résultat:
select * from
(
select
i.item_name
, c.color_name
from
item i
, color c
, item_color ic
where
ic.item_id = i.id
and ic.color_id = c.id
) pivot xml (
count(color_name) cnt
for color_name in (any)
)
donne:
item 1 <PivotSet><item><column name = "COLOR_NAME">green</column><column name = "CNT">1</column></item><item><column name = "COLOR_NAME">red</column><column name = "CNT">1</column></item></PivotSet>
item 2 <PivotSet><item><column name = "COLOR_NAME">blue</column><column name = "CNT">1</column></item><item><column name = "COLOR_NAME">green</column><column name = "CNT">1</column></item></PivotSet>
item 3 <PivotSet><item><column name = "COLOR_NAME">blue</column><column name = "CNT">1</column></item></PivotSet>