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
È stato utile?

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

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