Ayudar a la construcción de una consulta SQL de varias tablas
Pregunta
Dadas las siguientes tablas, cómo podría yo crear una consulta SQL que incluye una lista de todos los artículos de los "elementos" de mesa, y una columna para cada color de la tabla "colores" que, para cada elemento de la lista, indica qué colores el artículo tiene una relación con.
Si eso está claro en absoluto, por favor hágamelo saber qué información adicional ayudará a aclarar. La información de la tabla y el resultado deseado SQL son a continuación:
artículos tabla:
id | item_name
1 | 'item 1'
2 | 'item 2'
3 | 'item 3'
tabla colores:
id | color_name
1 | 'red'
2 | 'blue'
3 | 'green'
tabla item_color:
item_id | color_id
1 | 1
1 | 3
2 | 2
2 | 3
3 | 2
deseado resultado de la consulta SQL:
item_name | red | blue | green
'item 1' | 1 | null | 1
'item 2' | null| 1 | 1
'item 3' | null| 1 | null
Gracias, Colin
Solución
Uso:
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
Cambiar MAX cuente si desea que el # total de rojo / azul / verde asociado a un elemento.
alternativo usando Subconsulta Factoring:
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
Otros consejos
¿Está usted en Oracle 11g?
Esto parece ser un uso ideal para el nuevo característica de pivote en 11g
Si usted sabe todos los colores posibles de antelación, puede hacerlo desordenadamente pero con eficacia. Si usted no sabe todos los colores posibles de antelación, es mucho más difícil - que tiene que ejecutar algunas consultas para averiguar qué columnas aparecerán en la tabla de resultados, y luego elaborar el código SQL para crear las columnas (SQL dinámico) .
Por lo tanto, vamos a suponer que usted sabe las columnas en la tabla de resultados:
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
Tenga en cuenta que en esta formulación, he utilizado los datos de los colores Mesa en la construcción de la consulta. Y la forma alternativa sería construir las sub-consultas como (interior) se une a la tabla de colores, usando el nombre del color en lugar del código en las cláusulas 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;
a continuación, seleccione:
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')
);
da:
item 1 1 0 1
item 2 0 1 1
item 3 0 1 0
en caso de que no conoce la lista de colores de antemano puede seleccionar la tabla de colores primero y luego construir el pivote selecciona dinámicamente (como una subselección for color_name in (select color_name from color)
no es posible) o, alternativamente, se puede utilizar pivot xml
y postproceso el resultado:
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)
)
da:
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>