我有一张表,每1次调查可存储1行 每项调查得到大约70个问题,每个栏目提出1个问题
SurveyID Q1, Q2 Q3 .....
1 Yes Good Bad ......
我想转动这个,所以它读取
SurveyID Question Answer
1 Q1 Yes
1 Q2 Good
1 Q3 Bad
... ... .....
我使用{cross apply}来实现这个
SELECT t.[SurveyID]
, x.question
, x.Answer
FROM tbl t
CROSS APPLY
(
select 1 as QuestionNumber, 'Q1' as Question , t.Q1 As Answer union all
select 2 as QuestionNumber, 'Q2' as Question , t.Q2 As Answer union all
select 3 as QuestionNumber, 'Q3' as Question , t.Q3 As Answer) x
这有效,但我不想这样做70次,所以我有这个选择陈述
select ORDINAL_POSITION
, COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = mytable
这为我提供了表中列和列位置的列表。 所以我希望我能以某种方式加入第二个语句,第一个语句是列名。但是,我在这里比较列和列标题中的内容。它可行吗?有没有其他方法来实现这一目标?
希望你能指导我吗?
谢谢
答案 0 :(得分:5)
您应该使用UNPIVOT
代替Cross Apply,而不是Cross Apply ....
MS SQL Server 2008架构设置:
CREATE TABLE Test_Table(SurveyID INT, Q1 VARCHAR(10)
, Q2 VARCHAR(10), Q3 VARCHAR(10), Q4 VARCHAR(10))
INSERT INTO Test_Table VALUES
(1 , 'Yes', 'Good' , 'Bad', 'Bad')
,(2 , 'Bad', 'Bad' , 'Yes' , 'Good')
查询1 :
SELECT SurveyID
,Questions
,Answers
FROM Test_Table t
UNPIVOT ( Answers FOR Questions IN (Q1,Q2,Q3,Q4))up
<强> Results 强>:
| SurveyID | Questions | Answers |
|----------|-----------|---------|
| 1 | Q1 | Yes |
| 1 | Q2 | Good |
| 1 | Q3 | Bad |
| 1 | Q4 | Bad |
| 2 | Q1 | Bad |
| 2 | Q2 | Bad |
| 2 | Q3 | Yes |
| 2 | Q4 | Good |
答案 1 :(得分:0)
如果您需要对许多具有不同列数的类似表执行此类操作,单独使用UNPIVOT
方法可能会很烦人,因为您必须手动更改列列表({{1} }) 每一次。
问题中基于Q1,Q2,Q3,etc
的查询也存在类似的缺点。
正如您所猜测的,解决方案涉及使用服务器维护的元信息来告诉您需要操作的列的列表。但是,您可能不需要某种 join ,而是需要动态SQL ,即一个即时创建另一个SQL查询的SQL查询。
这主要是通过在查询的CROSS APPLY
部分中连接字符串(varchar)信息来完成的,包括SELECT
(和join)子句中可用列的值。
使用动态SQL(DSQL)方法,您经常使用系统元表作为起点。某些SQL Server版本中存在FROM
,但您最好使用Object Catalog Views。
为您的INFORMATION_SCHEMA
方法生成代码的原型DSQL解决方案如下所示:
CROSS APPLY
可以使用类似的方法为-- Create a variable to hold the created SQL code
-- First, add the static code at the start:
declare @SQL varchar(max) =
' SELECT t.[SurveyID]
, x.question
, x.Answer
FROM tbl t
CROSS APPLY
(
'
-- This syntax will add to the variable for every row in the query results; it's a little like looping over all the rows.
select @SQL +=
'select ' + cast(C.column_id as varchar)
+ ' as QuestionNumber, ''' + C.name
+ ''' as Question , t.' + C.name
+ ' As Answer union all
'
from sys.columns C
inner join sys.tables T on C.object_id=T.object_id
where T.name = 'MySurveyTable'
-- Remove final "union all", add closing bracket and alias
set @SQL = left(@SQL,len(@SQL)-10) + ') x'
print @SQL
-- To also execute (run) the dynamically-generated SQL
-- and get your desired row-based output all at the same time,
-- use the EXECUTE keyword (EXEC for short)
exec @SQL
方法动态编写SQL。