SQL 查询行到列
SQL query rows to columns
编辑:我使用 Microsoft SQL Server Management Studio 来 运行 我的查询。
我猜是 Microsoft SQL 服务器标准版(64 位)。
我对 运行 有一个复杂的查询。我不知道该怎么做,所以我去写了一个大约有 500 行和许多连接的查询。不应该是圆顶的样子。
我的数据结构是:
id user_id question_id answer1
1 1 1 a
2 1 2 c
3 1 3 a
4 2 1 c
5 2 2 a
... ... ... ...
有 700 多个用户。每个用户已经回答了大约 60 个问题(乘以 2,每个问题有 2 个答案,但如果我能得到第一个答案的一个很好的查询,这就无关紧要了)。有些问题我不感兴趣(实际上应该跳过)。
我目前的结果如下(结果不错,但查询太复杂了):
user_id q1 q2 q3 q4 q8 q9 ... q60
1 a b c d b a ... a
2 b a c a c b ... w
3 y a w ... ...
所以,基本上我想创建一个数组,比如说 [1,2,3,4,8,9]
,说我对那些问题 ID 感兴趣,然后查询,所以我得到了上面示例中的那些列。我不知道该怎么做。
我当前的查询是:
SELECT C.user_id, Q1, Q2, Q3, Q4, Q8, ...
FROM (
SELECT A.user_id, Q1, // and here tons of unions
编辑:仅使用 answer1 进行了简化:
DECLARE @tbl TABLE(id INT,user_id INT,question_id INT,answer1 VARCHAR(1),answer2 VARCHAR(1));
INSERT INTO @tbl VALUES
(1,1,1,'a','x')
,(2,1,2,'c','y')
,(3,1,3,'a','y')
,(4,2,1,'c','y')
,(5,2,2,'a','x');
WITH AllAnswers AS
(
SELECT p.*
FROM
(
SELECT tbl.user_id
,'q' + CAST(tbl.question_id AS VARCHAR(10)) AS columnName
,answer1
FROM @tbl AS tbl
) AS x
PIVOT
(
MIN(answer1) FOR columnName IN(q1,q2,q3 /*Add your question numbers here*/)
) AS p
)
SELECT aa.user_id
,aa.q1
,aa.q2
,aa.q3
/*Get only the questions you want*/
FROM AllAnswers AS aa
/* Result
user_id q1 q2 q3
1 a c a
2 c a NULL
*/
这是否适合您:
只是一个简短的解释:当你为每个问题写两个答案时,我将第二个答案放入测试集中。为了允许 PIVOT 包含多个列,我使用了将两个答案连接为伪 XML 的技巧。这再次被其内部索引旋转和分开。
结果是所有用户的列表,其中包含所有问题的所有答案。最后 SELECT 您可以选择要获取的问题/答案。
DECLARE @tbl TABLE(id INT,user_id INT,question_id INT,answer1 VARCHAR(1),answer2 VARCHAR(1));
INSERT INTO @tbl VALUES
(1,1,1,'a','x')
,(2,1,2,'c','y')
,(3,1,3,'a','y')
,(4,2,1,'c','y')
,(5,2,2,'a','x');
WITH AllAnswers AS
(
SELECT p.user_id
,CAST(p.q1 AS XML).value('x[1]','varchar(1)') AS q1_1
,CAST(p.q1 AS XML).value('x[2]','varchar(1)') AS q1_2
,CAST(p.q2 AS XML).value('x[1]','varchar(1)') AS q2_1
,CAST(p.q2 AS XML).value('x[2]','varchar(1)') AS q2_2
,CAST(p.q3 AS XML).value('x[1]','varchar(1)') AS q3_1
,CAST(p.q3 AS XML).value('x[2]','varchar(1)') AS q3_2
/*Add all your question numbers here*/
FROM
(
SELECT tbl.user_id
,'q' + CAST(tbl.question_id AS VARCHAR(10)) AS columnName
,'<x>' + ISNULL(answer1,'') + '</x><x>' + ISNULL(answer2,'') + '</x>' AS BothAnswers
FROM @tbl AS tbl
) AS x
PIVOT
(
MIN(BothAnswers) FOR columnName IN(q1,q2,q3 /*Add your question numbers here*/)
) AS p
)
SELECT aa.user_id
,aa.q1_1
,aa.q1_2
,aa.q2_1
,aa.q2_2
,aa.q3_1
,aa.q3_2
/*Get only the questions you want*/
FROM AllAnswers AS aa
SELECT *
FROM
(
SELECT [user_id],
[answer1],
row_number() OVER(PARTITION BY [user_id] ORDER BY [question_id]) rn
FROM [table]
) d
PIVOT
(
MAX([answer1])
FOR rn in ([1], [2], [3], [4], [5], [6])
) piv
效果很好,只有一个错误。 user_id = 1
没有 question_id = 3
的答案,但有 question_id = 4
的答案。我的结果将 4
上的答案放入 3
:
user_id 1 2 3 4 5 6
1 a b c NULL NULL
2 a b c d NULL NULL
有了这个数据:
user_id question_id answer1
1 1 a
1 2 b
1 4 c
1 5 (anwer1 = empty string)
1 6 NULL
2 1 a
2 2 b
2 4 c
2 5 d
2 6 NULL
应该给出:
user_id 1 2 3 4 5 6
1 a b NULL c NULL
2 a b NULL c d NULL
所以错误:如果没有找到记录,则使用 'next question' 的答案。
编辑:我使用 Microsoft SQL Server Management Studio 来 运行 我的查询。 我猜是 Microsoft SQL 服务器标准版(64 位)。
我对 运行 有一个复杂的查询。我不知道该怎么做,所以我去写了一个大约有 500 行和许多连接的查询。不应该是圆顶的样子。
我的数据结构是:
id user_id question_id answer1
1 1 1 a
2 1 2 c
3 1 3 a
4 2 1 c
5 2 2 a
... ... ... ...
有 700 多个用户。每个用户已经回答了大约 60 个问题(乘以 2,每个问题有 2 个答案,但如果我能得到第一个答案的一个很好的查询,这就无关紧要了)。有些问题我不感兴趣(实际上应该跳过)。
我目前的结果如下(结果不错,但查询太复杂了):
user_id q1 q2 q3 q4 q8 q9 ... q60
1 a b c d b a ... a
2 b a c a c b ... w
3 y a w ... ...
所以,基本上我想创建一个数组,比如说 [1,2,3,4,8,9]
,说我对那些问题 ID 感兴趣,然后查询,所以我得到了上面示例中的那些列。我不知道该怎么做。
我当前的查询是:
SELECT C.user_id, Q1, Q2, Q3, Q4, Q8, ...
FROM (
SELECT A.user_id, Q1, // and here tons of unions
编辑:仅使用 answer1 进行了简化:
DECLARE @tbl TABLE(id INT,user_id INT,question_id INT,answer1 VARCHAR(1),answer2 VARCHAR(1));
INSERT INTO @tbl VALUES
(1,1,1,'a','x')
,(2,1,2,'c','y')
,(3,1,3,'a','y')
,(4,2,1,'c','y')
,(5,2,2,'a','x');
WITH AllAnswers AS
(
SELECT p.*
FROM
(
SELECT tbl.user_id
,'q' + CAST(tbl.question_id AS VARCHAR(10)) AS columnName
,answer1
FROM @tbl AS tbl
) AS x
PIVOT
(
MIN(answer1) FOR columnName IN(q1,q2,q3 /*Add your question numbers here*/)
) AS p
)
SELECT aa.user_id
,aa.q1
,aa.q2
,aa.q3
/*Get only the questions you want*/
FROM AllAnswers AS aa
/* Result
user_id q1 q2 q3
1 a c a
2 c a NULL
*/
这是否适合您:
只是一个简短的解释:当你为每个问题写两个答案时,我将第二个答案放入测试集中。为了允许 PIVOT 包含多个列,我使用了将两个答案连接为伪 XML 的技巧。这再次被其内部索引旋转和分开。
结果是所有用户的列表,其中包含所有问题的所有答案。最后 SELECT 您可以选择要获取的问题/答案。
DECLARE @tbl TABLE(id INT,user_id INT,question_id INT,answer1 VARCHAR(1),answer2 VARCHAR(1));
INSERT INTO @tbl VALUES
(1,1,1,'a','x')
,(2,1,2,'c','y')
,(3,1,3,'a','y')
,(4,2,1,'c','y')
,(5,2,2,'a','x');
WITH AllAnswers AS
(
SELECT p.user_id
,CAST(p.q1 AS XML).value('x[1]','varchar(1)') AS q1_1
,CAST(p.q1 AS XML).value('x[2]','varchar(1)') AS q1_2
,CAST(p.q2 AS XML).value('x[1]','varchar(1)') AS q2_1
,CAST(p.q2 AS XML).value('x[2]','varchar(1)') AS q2_2
,CAST(p.q3 AS XML).value('x[1]','varchar(1)') AS q3_1
,CAST(p.q3 AS XML).value('x[2]','varchar(1)') AS q3_2
/*Add all your question numbers here*/
FROM
(
SELECT tbl.user_id
,'q' + CAST(tbl.question_id AS VARCHAR(10)) AS columnName
,'<x>' + ISNULL(answer1,'') + '</x><x>' + ISNULL(answer2,'') + '</x>' AS BothAnswers
FROM @tbl AS tbl
) AS x
PIVOT
(
MIN(BothAnswers) FOR columnName IN(q1,q2,q3 /*Add your question numbers here*/)
) AS p
)
SELECT aa.user_id
,aa.q1_1
,aa.q1_2
,aa.q2_1
,aa.q2_2
,aa.q3_1
,aa.q3_2
/*Get only the questions you want*/
FROM AllAnswers AS aa
SELECT *
FROM
(
SELECT [user_id],
[answer1],
row_number() OVER(PARTITION BY [user_id] ORDER BY [question_id]) rn
FROM [table]
) d
PIVOT
(
MAX([answer1])
FOR rn in ([1], [2], [3], [4], [5], [6])
) piv
效果很好,只有一个错误。 user_id = 1
没有 question_id = 3
的答案,但有 question_id = 4
的答案。我的结果将 4
上的答案放入 3
:
user_id 1 2 3 4 5 6
1 a b c NULL NULL
2 a b c d NULL NULL
有了这个数据:
user_id question_id answer1
1 1 a
1 2 b
1 4 c
1 5 (anwer1 = empty string)
1 6 NULL
2 1 a
2 2 b
2 4 c
2 5 d
2 6 NULL
应该给出:
user_id 1 2 3 4 5 6
1 a b NULL c NULL
2 a b NULL c d NULL
所以错误:如果没有找到记录,则使用 'next question' 的答案。