Concatena più campi in uno solo con SQL
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.
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.