SQL Server 2000:Idee per l'esecuzione di concatenazione di aggregazione sottoquery
-
18-09-2019 - |
Domanda
ho una query che restituisce le righe che voglio, ad esempio
QuestionID QuestionTitle UpVotes DownVotes
========== ============= ======= =========
2142075 Win32: Cre... 0 0
2232727 Win32: How... 2 0
1870139 Wondows Ae... 12 0
Ora voglio avere un colonna restituiti, che contiene un elenco separato da virgole di "Autori"(ad es.poster originale ed editori).ad esempio:
QuestionID QuestionTitle UpVotes DownVotes Authors
========== ============= ======= ========= ==========
2142075 Win32: Cre... 0 0 Ian Boyd
2232727 Win32: How... 2 0 Ian Boyd, roygbiv
1870139 Wondows Ae... 12 0 Ian Boyd, Aaron Klotz, Jason Diller, danbystrom
Faking It
SQL Server 2000 non dispone di un CONCAT(AuthorName, ', ')
operazione di aggregazione, sono stato a fare finta di non - esecuzione di semplici sub-seleziona per il TOP 1
autore, e l'autore del conte.
QuestionID QuestionTitle UpVotes DownVotes FirstAuthor AuthorCount
========== ============= ======= ========= =========== ===========
2142075 Win32: Cre... 0 0 Ian Boyd 1
2232727 Win32: How... 2 0 Ian Boyd 2
1870139 Wondows Ae... 12 0 Ian Boyd 3
Se c'è più di un autore, poi, mostrano all'utente un'ellissi ("..."), per indicare che c'è più di uno.ad es.l'utente dovrebbe vedere:
QuestionID QuestionTitle UpVotes DownVotes Authors
========== ============= ======= ========= ==========
2142075 Win32: Cre... 0 0 Ian Boyd
2232727 Win32: How... 2 0 Ian Boyd, …
1870139 Wondows Ae... 12 0 Ian Boyd, …
E che funziona abbastanza bene, in quanto normalmente un domanda non è stata modificata - il che significa che sto sostenendo il 99% caso perfettamente, e l ' 1% caso solo la metà-assed come bene.
Filettato Ri-query
Come più complicata e soggetta a bug soluzione, stavo pensando a scorrere l'elenco visualizzato, e girando un thread del pool di thread di lavoro per ogni "domanda"nell'elenco, eseguire una query al database per ottenere la lista degli autori, quindi l'aggregazione elenco in memoria.Questo significa che la lista si riempie prima la (nativo) applicazione.Poi ho problema un paio di migliaia di singole query in seguito.
Ma sarebbe terribilmente, terribilmente, terribilmente lenta.Per non parlare di bug crivellato, dal momento che sarà thread di lavoro.
Sì, sì, sì
Adam Meccanico dice abbastanza chiaramente:
Non concatenare le righe in delimitato stringhe SQL Server.Farlo client lato.
Dimmi come, e io lo farò.
/piangere
Qualcuno può pensare che la soluzione migliore, che è più veloce (diciamo...all'interno di un ordine di grandezza) rispetto al mio originale "TOP 1 plus ellissi" soluzione?
Per esempio, c'è un modo per restituire un set di risultati, dove raggiungere riga è associato un set di risultati?Così, per ogni "maestro" di riga, ho potuto ottenere un "dettaglio" risultati, che contiene l'elenco.
Codice per la miglior risposta
Cade la link Adam Machanic soluzione mi piace il meglio.Una funzione definita dall'utente, che sembra funzionare tramite la magia:
CREATE FUNCTION dbo.ConcatAuthors(@QuestionID int)
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE @Output VARCHAR(8000)
SET @Output = ''
SELECT @Output = CASE @Output
WHEN '' THEN AuthorName
ELSE @Output + ', ' + AuthorName
END
FROM (
SELECT QuestionID, AuthorName, QuestionDate AS AuthorDate FROM Questions
UNION
SELECT QuestionID, EditorName, EditDate FROM QuestionEdits
) dt
WHERE dt.QuestionID = @QuestionID
ORDER BY AuthorDate
RETURN @Output
END
Con una T-SQL utilizzo di:
SELECT QuestionID, QuestionTitle, UpVotes, DownVotes, dbo.ConcatAuthors(AuthorID)
FROM Questions
Soluzione
Dai un'occhiata a questi articoli:
http://dataeducation.com/rowset-string-concatenation-which-method-is-best/
http://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/ (Vedere Phil Fattore di cross join soluzione nelle risposte, che lavorerà in SQL Server 2000)
Ovviamente in SQL Server 2005, è possibile che l'XML trucco è più semplice, più flessibile e generalmente più performante.
Come lontano come la restituzione di un set di righe per ogni riga, se avete ancora voglia di fare che, per qualche motivo, è possibile farlo in una stored procedure, ma il cliente avrà bisogno di consumare tutte le righe nel primo set di righe e poi passare al successivo set di righe e di associarlo con la prima riga del primo set di righe, etc.SP necessario aprire un cursore sullo stesso set è restituito come primo set di righe e di eseguire più seleziona in sequenza per generare il bambino set di righe.È una tecnica che ho fatto, ma solo dove TUTTI i dati in realtà era necessario (per esempio, in un sistema completamente popolato vista ad albero).
E a prescindere da quello che la gente dice di farlo lato client è spesso un grande spreco di banda, perché la restituzione di tutte le righe e fare il looping e di rottura nel lato client significa che il numero enorme di identico colonne sono trasferiti all'inizio di ogni riga solo per ottenere la modifica colonna alla fine della riga.
Ovunque ti trovi, dovrebbe essere un decisione informata basato su il caso d'uso.
Altri suggerimenti
Ho provato 3 approcci a questa soluzione, quello postato qui, activex scripting e UDF funzioni.
Il più efficace script (speed-saggio) per me è stato bizzarely Axtive-X in esecuzione di script più query per ottenere il additioanl dati concat.
FSU ha preso una media di 22 minuti per trasformare la Subquery metodo (pubblicato qui) ha preso circa 5m e activeX script ha preso 4m30, con mio grande fastidio poiché questo è lo script speravo di fossa.Dovrò vedere se riesco a stirare un paio di ulteriori efficienze altrove.
Penso che l'ulteriore 30 anni è utilizzato da tempdb essere utilizzato per memorizzare i dati dal mio script richiede un ordine.
Va notato che io sono concatanating enorme quantità di dati testuali.
Si può anche dare un'occhiata a questo script.Si tratta fondamentalmente di un cross join approccio che Cade Roux anche menzionato nel suo post.
L'approccio sembra molto pulita:devi fare una vista prima e, in secondo luogo, creare una dichiarazione basata sui valori della vista.La seconda istruzione sql è possibile costruire in modo dinamico nel codice, quindi dovrebbe essere semplice da usare.
Non sono sicuro se questo funziona in SQL Server 2000, ma si può provare:
--combine parent and child, children are CSV onto parent row
CREATE TABLE #TableA (RowID int, Value1 varchar(5), Value2 varchar(5))
INSERT INTO #TableA VALUES (1,'aaaaa','A')
INSERT INTO #TableA VALUES (2,'bbbbb','B')
INSERT INTO #TableA VALUES (3,'ccccc','C')
CREATE TABLE #TableB (RowID int, TypeOf varchar(10))
INSERT INTO #TableB VALUES (1,'wood')
INSERT INTO #TableB VALUES (2,'wood')
INSERT INTO #TableB VALUES (2,'steel')
INSERT INTO #TableB VALUES (2,'rock')
INSERT INTO #TableB VALUES (3,'plastic')
INSERT INTO #TableB VALUES (3,'paper')
SELECT
a.*,dt.CombinedValue
FROM #TableA a
LEFT OUTER JOIN (SELECT
c1.RowID
,STUFF(
(SELECT
', ' + TypeOf
FROM (SELECT
a.RowID,a.Value1,a.Value2,b.TypeOf
FROM #TableA a
LEFT OUTER JOIN #TableB b ON a.RowID=b.RowID
) c2
WHERE c2.rowid=c1.rowid
ORDER BY c1.RowID, TypeOf
FOR XML PATH('')
)
,1,2, ''
) AS CombinedValue
FROM (SELECT
a.RowID,a.Value1,a.Value2,b.TypeOf
FROM #TableA a
LEFT OUTER JOIN #TableB b ON a.RowID=b.RowID
) c1
GROUP BY RowID
) dt ON a.RowID=dt.RowID
USCITA da SQL Server 2005:
RowID Value1 Value2 CombinedValue
----------- ------ ------ ------------------
1 aaaaa A wood
2 bbbbb B rock, steel, wood
3 ccccc C paper, plastic
(3 row(s) affected)
MODIFICA query che sostituisce PER XML PATH FOR XML RAW, quindi questo dovrebbe funzionare su SQL Server 2000
SELECT
a.*,dt.CombinedValue
FROM #TableA a
LEFT OUTER JOIN (SELECT
c1.RowID
,STUFF(REPLACE(REPLACE(
(SELECT
', ' + TypeOf as value
FROM (SELECT
a.RowID,a.Value1,a.Value2,b.TypeOf
FROM #TableA a
LEFT OUTER JOIN #TableB b ON a.RowID=b.RowID
) c2
WHERE c2.rowid=c1.rowid
ORDER BY c1.RowID, TypeOf
FOR XML RAW
)
,'<row value="',''),'"/>','')
, 1, 2, '') AS CombinedValue
FROM (SELECT
a.RowID,a.Value1,a.Value2,b.TypeOf
FROM #TableA a
LEFT OUTER JOIN #TableB b ON a.RowID=b.RowID
) c1
GROUP BY RowID
) dt ON a.RowID=dt.RowID
USCITA, stessa query originale