Pergunta

eu tenho uma consulta que retorna linhas que eu quero, por exemplo,

QuestionID  QuestionTitle  UpVotes  DownVotes  
==========  =============  =======  =========  
2142075     Win32: Cre...        0          0  
2232727     Win32: How...        2          0  
1870139     Wondows Ae...       12          0  

Agora eu quero ter um coluna voltou, que contém uma lista separada por vírgulas "Autores"(e.g.poster original e editores).por exemplo:

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


Fingir

SQL Server 2000 não tem um CONCAT(AuthorName, ', ') agregação de operação, eu tenho de fingir - efectuar uma simples sub-seleciona para o TOP 1 autor, e o autor de contagem.

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 houver mais de um autor, então eu mostrar ao usuário uma reticências ("..."), para indicar que existe mais do que um.exemplo:o usuário poderia ver:

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 que funciona bem o suficiente, pois, normalmente, um pergunta não é editado, o que significa que eu estou apoiando a 99% caso perfeitamente, e de 1% no caso de apenas a metade-assed bem.


Rosca Re-consulta

Como ser mais complicado, e bug propensas a solução, eu estava pensando em iterar a lista apresentada, e girando até que um thread pool de thread de trabalho para cada um "pergunta"na lista, execute uma consulta ao banco de dados para obter a lista de autores, agregando a lista na memória.Isto significa que a lista preenche o primeiro na (nativo) aplicações.Em seguida, eu o problema de alguns milhares de consultas individuais depois.

Mas o que seria terrivelmente, terrivelmente, terrivelmente lento.Para não mencionar o erro crivado, pois vai ser o thread de trabalho.


Yeah yeah yeah

Adam Mecânico diz muito claramente:

Não concatenar linhas delimitado cadeias de caracteres no SQL Server.Fazê-lo de cliente o lado.

Diga-me como e que eu vou fazer.


/cry

Alguém pode pensar em uma solução melhor, que é mais rápido (dizer...dentro de uma ordem de magnitude) do que o meu original "TOP 1 mais reticências" solução?

Por exemplo, existe uma maneira de retornar um conjunto de resultados, onde a chegar a linha tem associado um conjunto de resultados?Assim, para cada "mestre" linha", eu poderia chegar a um "detalhe" conjunto de resultados que contém a lista.


Código para melhor resposta

Cade link para Adam Machanic da solução eu como a melhor.Uma função definida pelo usuário, que parece operar através de 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

Com uma T-SQL uso de:

SELECT QuestionID, QuestionTitle, UpVotes, DownVotes, dbo.ConcatAuthors(AuthorID)
FROM Questions
Foi útil?

Solução

Dê uma olhada nesses artigos:

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/ (Veja a solução de junção cruzada de Phil Factor nas respostas - que funcionarão no SQL Server 2000)

Obviamente, no SQL Server 2005, o truque para XML é mais fácil, mais flexível e geralmente mais desempenhado.

No que diz respeito ao retorno de um lixo para cada linha, se você ainda quiser fazer isso por algum motivo, poderá fazer isso em um procedimento armazenado, mas o cliente precisará consumir todas as linhas no primeiro lime e depois ir para o próximo linhas de linhas e associá -lo à primeira linha no primeiro lixo, etc. Seu SP precisaria abrir um cursor no mesmo conjunto que ele retornou como o primeiro lixo e executar várias seleções em sequência para gerar todas as linhas infantis. É uma técnica que eu fiz, mas apenas onde TUDO Os dados eram realmente necessários (por exemplo, em uma vista de árvore totalmente povoada).

E, independentemente do que as pessoas dizem, fazer isso ao lado do cliente geralmente é um grande desperdício de largura de banda, porque devolver todas as fileiras e fazer o loop e quebrar no lado do cliente significa que um grande número de colunas idênticas está sendo transferido no início do início do Cada linha apenas para obter a coluna de mudança no final da linha.

Onde quer que você faça isso, deve ser um decisão informada baseado em sua Caso de uso.

Outras dicas

Eu tentei 3 abordagens para esta solução, a uma postado aqui, activex, scripts e funções UDF.

O mais eficaz script (velocidade-wise) para mim foi bizzarely Axtive-X script executando várias consultas para obter o additioanl dados para concat.

UDF teve uma média de 22 minutos para transformar, a Subconsulta método (postado aqui) levou cerca de 5m e o script activeX tomou 4m30, tanto para o meu aborrecimento, já que este foi o script que eu estava esperando para vala.Eu vou ter que ver se eu consigo resolver alguns mais eficiência em outro lugar.

Eu acho que o adicional de 30, é usado pelo tempdb está sendo usada para armazenar os dados, pois o meu script requer um order by.

Deve ser notado que eu sou concatanating enormes quantidades de dados textuais.

Você também pode dar uma olhada nisso roteiro. É basicamente a abordagem de junção cruzada que Cade Roux também mencionou em seu post.

A abordagem acima parece muito limpa: você deve fazer uma exibição primeiro e em segundo lugar, criar uma instrução com base nos valores na visualização. A segunda instrução SQL que você pode construir dinamicamente em seu código, para que seja direto para o uso.

Não tenho certeza se isso funciona no SQL Server 2000, mas você pode tentar:

--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

Saída do 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)

EDITAR Consulta que substitui o caminho XML pelo XML RAW, então isso deve funcionar no 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

Saída, o mesmo que a consulta original

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top