格式化从动态数据透视中获得的锯齿状数据
Format Jagged data gained from dynamic pivot
我需要格式化并从数据库中提取一些数据。虽然我可以成功提取数据,但我正在努力应对它的参差不齐的特性。
我有以下内容:
create table temp
(
QuestionID INT,
AnswerID INT,
AnswerValue NVARCHAR(50)
)
insert into temp values (1, 1, 'Ans C')
insert into temp values (1, 2, 'Ans B')
insert into temp values (1, 3, 'Ans A')
insert into temp values (2, 4, 'Ans D')
insert into temp values (2, 5, 'Ans E')
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.AnswerID)
FROM temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT QuestionID, ' + @cols + ' from
(
select QuestionID
, AnswerValue
, AnswerID
from temp
) x
pivot
(
max(AnswerValue)
for AnswerID in (' + @cols + ')
) p '
execute(@query)
drop table temp
执行此生成
+------------+-------+-------+-------+-------+-------+
| QuestionID | 1 | 2 | 3 | 4 | 5 |
+------------+-------+-------+-------+-------+-------+
| 1 | Ans C | Ans B | Ans A | NULL | NULL |
| 2 | NULL | NULL | NULL | Ans D | Ans E |
+------------+-------+-------+-------+-------+-------+
我只需要这样格式化就可以了
+------------+-------+-------+-------+
| QuestionID | Q1 | Q2 | Q3 |
+------------+-------+-------+-------+
| 1 | Ans C | Ans B | Ans A |
| 2 | NULL | Ans D | Ans E |
+------------+-------+-------+-------+
请注意,由于限制,这需要在 SQL 中完成,而不是像 c# 这样的高级语言。
代码有几处错误。首先,您正在使用 AnswerID
创建您的列列表,因此数据被拆分到多个列而不是每个问题的答案。
为了解决这个问题,您需要使用 row_number()
之类的窗口函数为每个 question/answer 组合创建一个序列。
创建动态列时,将代码更改为:
SET @cols = STUFF((SELECT ',' + QUOTENAME('Q'+cast(rn as varchar(10)))
FROM
(
SELECT rn = row_number() over(partition by QuestionID
order by AnswerID)
FROM temp
) c
group by rn
order by rn
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
这将使用 row_number() 并将根据 QuestionID
创建列名。然后你将在你的子查询中包含 row_number()
使你的代码:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
SET @cols = STUFF((SELECT ',' + QUOTENAME('Q'+cast(rn as varchar(10)))
FROM
(
SELECT rn = row_number() over(partition by QuestionID
order by AnswerID)
FROM temp
) c
group by rn
order by rn
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT QuestionID, ' + @cols + '
from
(
select QuestionID
, AnswerValue
, col = ''Q''+ cast(row_number() over(partition by QuestionID
order by AnswerID) as varchar(10))
from temp
) x
pivot
(
max(AnswerValue)
for col in (' + @cols + ')
) p '
exec sp_executesql @query;
参见SQL Fiddle with Demo.这给出了一个结果:
| QUESTIONID | Q1 | Q2 | Q3 |
|------------|-------|-------|--------|
| 1 | Ans C | Ans B | Ans A |
| 2 | Ans D | Ans E | (null) |
您可以使用这部分代码:
SELECT 'A' + CAST(ROW_NUMBER() OVER(PARTITION BY QuestionID ORDER BY Answer) AS VARCHAR(10)) AS cName
FROM tblAnswers
以便生成所需的列名。上面给你的东西像:
cName
-----
A1
A2
A3
A1
A2
您随后可以在动态数据透视表中使用上述内容以获得所需的结果:
DECLARE @cols AS NVARCHAR(MAX), @query AS NVARCHAR(MAX);
SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(a.cName)
FROM (
SELECT 'A' + CAST(ROW_NUMBER() OVER(PARTITION BY QuestionID ORDER BY Answer) AS VARCHAR(10)) AS cName
FROM tblAnswers
) a
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'),1,1,'')
set @query = 'SELECT Question, ' + @cols + ' ' +
'FROM (
SELECT q.Question, a.Answer,
''A'' + CAST(ROW_NUMBER() OVER(PARTITION BY a.QuestionID ORDER BY Answer) AS VARCHAR(10)) AS cName
FROM tblAnswers AS a
INNER JOIN tblQuestions AS q ON a.QuestionID = q.QuestionID
) t
PIVOT
(
MAX(t.Answer)
FOR cName in (' + @cols + ')
) Pvt '
execute(@query)
上面的输出如下:
Question A1 A2 A3
-----------------------------------
Q1 Answer1 Answer2 Answer3
Q2 Answer4 Answer5 NULL
我需要格式化并从数据库中提取一些数据。虽然我可以成功提取数据,但我正在努力应对它的参差不齐的特性。
我有以下内容:
create table temp
(
QuestionID INT,
AnswerID INT,
AnswerValue NVARCHAR(50)
)
insert into temp values (1, 1, 'Ans C')
insert into temp values (1, 2, 'Ans B')
insert into temp values (1, 3, 'Ans A')
insert into temp values (2, 4, 'Ans D')
insert into temp values (2, 5, 'Ans E')
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.AnswerID)
FROM temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT QuestionID, ' + @cols + ' from
(
select QuestionID
, AnswerValue
, AnswerID
from temp
) x
pivot
(
max(AnswerValue)
for AnswerID in (' + @cols + ')
) p '
execute(@query)
drop table temp
执行此生成
+------------+-------+-------+-------+-------+-------+
| QuestionID | 1 | 2 | 3 | 4 | 5 |
+------------+-------+-------+-------+-------+-------+
| 1 | Ans C | Ans B | Ans A | NULL | NULL |
| 2 | NULL | NULL | NULL | Ans D | Ans E |
+------------+-------+-------+-------+-------+-------+
我只需要这样格式化就可以了
+------------+-------+-------+-------+
| QuestionID | Q1 | Q2 | Q3 |
+------------+-------+-------+-------+
| 1 | Ans C | Ans B | Ans A |
| 2 | NULL | Ans D | Ans E |
+------------+-------+-------+-------+
请注意,由于限制,这需要在 SQL 中完成,而不是像 c# 这样的高级语言。
代码有几处错误。首先,您正在使用 AnswerID
创建您的列列表,因此数据被拆分到多个列而不是每个问题的答案。
为了解决这个问题,您需要使用 row_number()
之类的窗口函数为每个 question/answer 组合创建一个序列。
创建动态列时,将代码更改为:
SET @cols = STUFF((SELECT ',' + QUOTENAME('Q'+cast(rn as varchar(10)))
FROM
(
SELECT rn = row_number() over(partition by QuestionID
order by AnswerID)
FROM temp
) c
group by rn
order by rn
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
这将使用 row_number() 并将根据 QuestionID
创建列名。然后你将在你的子查询中包含 row_number()
使你的代码:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
SET @cols = STUFF((SELECT ',' + QUOTENAME('Q'+cast(rn as varchar(10)))
FROM
(
SELECT rn = row_number() over(partition by QuestionID
order by AnswerID)
FROM temp
) c
group by rn
order by rn
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT QuestionID, ' + @cols + '
from
(
select QuestionID
, AnswerValue
, col = ''Q''+ cast(row_number() over(partition by QuestionID
order by AnswerID) as varchar(10))
from temp
) x
pivot
(
max(AnswerValue)
for col in (' + @cols + ')
) p '
exec sp_executesql @query;
参见SQL Fiddle with Demo.这给出了一个结果:
| QUESTIONID | Q1 | Q2 | Q3 |
|------------|-------|-------|--------|
| 1 | Ans C | Ans B | Ans A |
| 2 | Ans D | Ans E | (null) |
您可以使用这部分代码:
SELECT 'A' + CAST(ROW_NUMBER() OVER(PARTITION BY QuestionID ORDER BY Answer) AS VARCHAR(10)) AS cName
FROM tblAnswers
以便生成所需的列名。上面给你的东西像:
cName
-----
A1
A2
A3
A1
A2
您随后可以在动态数据透视表中使用上述内容以获得所需的结果:
DECLARE @cols AS NVARCHAR(MAX), @query AS NVARCHAR(MAX);
SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(a.cName)
FROM (
SELECT 'A' + CAST(ROW_NUMBER() OVER(PARTITION BY QuestionID ORDER BY Answer) AS VARCHAR(10)) AS cName
FROM tblAnswers
) a
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'),1,1,'')
set @query = 'SELECT Question, ' + @cols + ' ' +
'FROM (
SELECT q.Question, a.Answer,
''A'' + CAST(ROW_NUMBER() OVER(PARTITION BY a.QuestionID ORDER BY Answer) AS VARCHAR(10)) AS cName
FROM tblAnswers AS a
INNER JOIN tblQuestions AS q ON a.QuestionID = q.QuestionID
) t
PIVOT
(
MAX(t.Answer)
FOR cName in (' + @cols + ')
) Pvt '
execute(@query)
上面的输出如下:
Question A1 A2 A3
-----------------------------------
Q1 Answer1 Answer2 Answer3
Q2 Answer4 Answer5 NULL