Linhas SQL para Colunas
-
19-09-2019 - |
Pergunta
Eu tenho uma tabela e quer transpor suas linhas em colunas, semelhante a uma tabela dinâmica, mas sem resumindo.
Por exemplo, eu tenho as seguintes tabelas:
Question
--QuestionID
--QuestionText
Response
--ResponseID
--ResponseText
--QuestionID
Basicamente eu quero ser capaz de criar uma tabela algo dinâmico como:
Question 1 Text | Question 2 Text | Question 3 Text
---------------------------------------------------
Response 1.1 Text | Response Text 1.2 | Response 1.3
Response 2.1 Text | Response Text 2.2 | Response 2.3
Response 3.1 Text | Response Text 3.2 | Response 3.3
Response 4.1 Text | Response Text 4.2 | Response 4.3
O requisito principal seria eu não sei no momento da concepção o que o texto da pergunta será.
Por favor, alguém pode me ajudar - Estou puxando meu cabelo para fora: oS
Essencialmente, você pode garantir que não haverá uma resposta para cada pergunta correspondente neste cenário.
Solução
Você não pode fazê-lo com SQL
(exceto com consultas dinâmicas), se você não sabe o número de colunas (i. E. Perguntas) em tempo de design.
Você deve puxar os dados que você quer em formato tabular e depois processá-lo no lado do cliente:
SELECT *
FROM Question
LEFT OUTER JOIN
Response
ON Response.QuestionId = Question.QuestionID
ou, provavelmente, este (em SQL Server 2005+
, Oracle 8i+
e PostgreSQL 8.4+
):
SELECT *
FROM (
SELECT q.*, ROW_NUMBER() OVER (ORDER BY questionID) AS rn
FROM Question q
) q
LEFT OUTER JOIN
(
SELECT r.*, ROW_NUMBER() OVER (PARTITION BY questionID ORDER BY ResponseID) AS rn
FROM Response r
) r
ON r.QuestionId = q.QuestionID
AND q.rn = r.rn
ORDER BY
q.rn, q.QuestionID
A última consulta lhe dará resultados nesta forma (desde que você tenha perguntas 4
):
rn question response
--- --- ---
1 Question 1 Response 1.1
1 Question 2 Response 2.1
1 Question 3 Response 3.1
1 Question 4 Response 4.1
2 Question 1 Response 1.2
2 Question 2 Response 2.2
2 Question 3 NULL
2 Question 4 Response 4.2
3 Question 1 NULL
3 Question 2 NULL
3 Question 3 Response 3.3
3 Question 4 NULL
, isto é a saída será os dados em forma de tabela, com rn
marcação do número de linha.
Cada vez que você vê o rn
mudança no cliente, você apenas perto <tr>
e abrir uma nova.
Você pode colocar com segurança um do seu <td>
por linha de resultados, uma vez que mesmo número ou linhas é garantida a ser retornado para cada rn
Esta é completamente uma pergunta freqüente.
SQL
não apenas uma ferramenta certa para retornar dados com número dinâmico de colunas.
SQL
opera em sets, eo layout da coluna é uma propriedade implícita de um set.
Você deve definir o layout do conjunto que você deseja obter em tempo de design, como você define o tipo de dados de um varible em C
.
C
trabalha com variáveis ??estritamente definidas, obras SQL
com conjuntos estritamente definidas.
Note que eu não estou dizendo que é o melhor método possível. É apenas as obras maneira SQL
.
Update:
Em SQL Server
, você pode puxar a mesa em forma HTML
direita para fora do banco de dados:
WITH a AS
(
SELECT a.*, ROW_NUMBER() OVER (PARTITION BY question_id ORDER BY id) AS rn
FROM answer a
),
rows AS (
SELECT ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM answer a
WHERE question_id =
(
SELECT TOP 1 question_id
FROM answer a
GROUP BY
question_id
ORDER BY
COUNT(*) DESC
)
)
SELECT (
SELECT COALESCE(a.value, '')
FROM question q
LEFT JOIN
a
ON a.rn = rows.rn
AND a.question_id = q.id
FOR XML PATH ('td'), TYPE
) AS tr
FROM rows
FOR XML PATH(''), ROOT('table')
Veja esta entrada no meu blog para mais detalhes:
Outras dicas
Faça o seu agrupamento e agregação de primeira, usando a resposta de Quassnoi como um resultado intermediário.
tabulação cruzada só deve ser feito quando você está não vai estar fazendo orientada conjunto operatons sobre os resultados. Alguns dialetos SQL têm palavras-chave como pivô, transformar ou CROSSTABULATE de conseguir isso, mas você é provavelmente melhor fora de usar XSLT.