Concatenar varios campos en uno con SQL
Pregunta
tengo tres mesas tag
, page
, pagetag
Con los datos a continuación
página
ID NAME
1 page 1
2 page 2
3 page 3
4 page 4
etiqueta
ID NAME
1 tag 1
2 tag 2
3 tag 3
4 tag 4
etiqueta de página
ID PAGEID TAGID
1 2 1
2 2 3
3 3 4
4 1 1
5 1 2
6 1 3
Me gustaría obtener una cadena que contenga los nombres de las etiquetas correspondientes para cada página con SQL en una sola consulta.Este es mi resultado deseado.
ID NAME TAGS
1 page 1 tag 1, tag 2, tag 3
2 page 2 tag 1, tag 3
3 page 3 tag 4
4 page 4
¿Es esto posible con SQL?
Estoy usando MySQL.No obstante, me gustaría una solución independiente del proveedor de bases de datos, si es posible.
Solución
Sergio del Amo:
Sin embargo, no recibo las páginas sin etiquetas.Supongo que necesito escribir mi consulta con combinaciones externas izquierdas.
SELECT pagetag.id, page.name, group_concat(tag.name)
FROM
(
page LEFT JOIN pagetag ON page.id = pagetag.pageid
)
LEFT JOIN tag ON pagetag.tagid = tag.id
GROUP BY page.id;
No es una consulta muy bonita, pero debería darte lo que quieres. pagetag.id
y group_concat(tag.name)
será null
para la página 4 en el ejemplo que publicó arriba, pero la página aparecerá en los resultados.
Otros consejos
Sí, puedes hacerlo en los 3, algo como lo siguiente:
SELECT page_tag.id, page.name, group_concat(tags.name)
FROM tag, page, page_tag
WHERE page_tag.page_id = page.page_id AND page_tag.tag_id = tag.id;
No se ha probado y probablemente podría escribirse de manera un poco más eficiente, ¡pero debería ayudarlo a comenzar!
Además, se supone MySQL, por lo que puede que no funcione tan bien con MSSQL.Y a MySQL no le gustan los guiones en los nombres de los campos, por lo que se cambiaron a guiones bajos en los ejemplos anteriores.
Hasta donde yo sé, SQL92 no define cómo se debe realizar la concatenación de cadenas.Esto significa que la mayoría de los motores tienen su propio método.
Si desea un método independiente de la base de datos, deberá hacerlo fuera de la base de datos.
(no probado en todos menos en Oracle)
Oráculo
SELECT field1 | ', ' | field2
FROM table;
Microsoft SQL
SELECT field1 + ', ' + field2
FROM table;
mysql
SELECT concat(field1,', ',field2)
FROM table;
PostgeSQL
SELECT field1 || ', ' || field2
FROM table;
Tengo una solución jugando con uniones.La consulta es:
SELECT
page.id AS id,
page.name AS name,
tagstable.tags AS tags
FROM page
LEFT OUTER JOIN
(
SELECT pagetag.pageid, GROUP_CONCAT(distinct tag.name) AS tags
FROM tag INNER JOIN pagetag ON tagid = tag.id
GROUP BY pagetag.pageid
)
AS tagstable ON tagstable.pageid = page.id
GROUP BY page.id
Y este será el resultado:
id name tags
---------------------------
1 page 1 tag2,tag3,tag1
2 page 2 tag1,tag3
3 page 3 tag4
4 page 4 NULL
¿Es posible aumentar la velocidad de la consulta escribiéndola de otra manera?
pagetag.id y group_concat(tag.name) serán nulos para la página 4 en el ejemplo que publicó anteriormente, pero la página aparecerá en los resultados.
Puedes usar el COALESCE
función para eliminar los nulos si necesita:
select COALESCE(pagetag.id, '') AS id ...
Devolverá el primer valor no nulo de su lista de parámetros.
Creo que es posible que necesites utilizar varias actualizaciones.
Algo como (no probado):
select ID as 'PageId', Name as 'PageName', null as 'Tags'
into #temp
from [PageTable]
declare @lastOp int
set @lastOp = 1
while @lastOp > 0
begin
update p
set p.tags = isnull(tags + ', ', '' ) + t.[Tagid]
from #temp p
inner join [TagTable] t
on p.[PageId] = t.[PageId]
where p.tags not like '%' + t.[Tagid] + '%'
set @lastOp == @@rowcount
end
select * from #temp
Aunque feo.
Ese ejemplo es T-SQL, pero creo que MySql tiene equivalentes a todo lo que se usa.