Domanda

Ho tre tavoli tag, page, pagetag

Con i dati qui sotto

pagina

ID      NAME
1       page 1
2       page 2
3       page 3
4       page 4

etichetta

ID      NAME
1       tag 1
2       tag 2
3       tag 3
4       tag 4

pagetag

ID   PAGEID  TAGID
1    2        1
2    2        3
3    3        4
4    1        1
5    1        2
6    1        3

Vorrei ottenere una stringa contenente i nomi dei tag corrispondenti per ogni pagina con SQL in un'unica query.Questo è il risultato desiderato.

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    

Questo è possibile con SQL?


Sto usando MySQL.Tuttavia, se possibile, vorrei una soluzione indipendente dal fornitore di database.

È stato utile?

Soluzione

Sergio dell'Amo:

Tuttavia, non ricevo le pagine senza tag.Immagino di dover scrivere la mia query con i join esterni sinistri.

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;

Non è una domanda molto carina, ma dovrebbe darti quello che vuoi - pagetag.id E group_concat(tag.name) sarà null per la pagina 4 nell'esempio che hai pubblicato sopra, ma la pagina verrà visualizzata nei risultati.

Altri suggerimenti

Sì, puoi farlo attraverso i 3 qualcosa di simile al seguente:

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;

Non è stato testato e probabilmente potrebbe essere scritto in modo un po' più efficiente, ma dovrebbe aiutarti a iniziare!

Inoltre, si presuppone MySQL, quindi potrebbe non funzionare così bene con MSSQL!E MySQL non ama i trattini nei nomi dei campi, quindi negli esempi precedenti sono stati sostituiti con caratteri di sottolineatura.

Per quanto ne so, SQL92 non definisce come dovrebbe essere eseguita la concatenazione delle stringhe.Ciò significa che la maggior parte dei motori ha il proprio metodo.

Se desideri un metodo indipendente dal database, dovrai farlo al di fuori del database.

(non testato in tutti tranne Oracle)

Oracolo

SELECT field1 | ', ' | field2
FROM table;

MSSQL

SELECT field1 + ', ' + field2
FROM table;

MySQL

SELECT concat(field1,', ',field2)
FROM table;

PostgeSQL

SELECT field1 || ', ' || field2
FROM table;

Ho trovato una soluzione giocando con i join.La domanda è:

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

E questo sarà l'output:

id   name    tags
---------------------------
1    page 1  tag2,tag3,tag1
2    page 2  tag1,tag3
3    page 3  tag4
4    page 4  NULL

È possibile aumentare la velocità della query scrivendola in un altro modo?

pagetag.id e group_concat(tag.name) saranno nulli per la pagina 4 nell'esempio che hai pubblicato sopra, ma la pagina apparirà nei risultati.

Puoi usare il COALESCE funzione per rimuovere i Null se è necessario:

select COALESCE(pagetag.id, '') AS id ...

Restituirà il primo valore non nullo dal suo elenco di parametri.

Penso che potrebbe essere necessario utilizzare più aggiornamenti.

Qualcosa del tipo (non testato):

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

Brutto però.

Questo esempio è T-SQL, ma penso che MySql abbia equivalenti a tutto ciò che viene utilizzato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top