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.

¿Fue útil?

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top