行列转换时,由于不知道要转换成列的字段有几种值,sql怎么写?
with a as (select stuid,subject,score from n881820_students_score where stuid = 10002)
select * from a
pivot (
sum(a.score) FOR subject IN ('语文','数学','英语')
)
ORDER BY stuid;
效果如下:
把IN ('语文','数学','英语') 换成IN (select distinct subject from n881820_students_score where stuid = 10002 )
报错:不允许将非常量表达式用于pivot|unpivo
with a as (select stuid,subject,score from n881820_students_score where stuid = 10002),
b as (select distinct subject from n881820_students_score where stuid = 10002)
select * from a
pivot (
sum(a.score) FOR subject IN (b.subject)
)
ORDER BY stuid;
您可以使用动态 SQL 来解决这个问题,动态 SQL 允许您在运行时动态地构建 SQL 查询。在这种情况下,您需要动态地构建 'FOR subject IN:
DECLARE @cols AS NVARCHAR(MAX)
DECLARE @query AS NVARCHAR(MAX)
-- 获取要转换的字段列表
SELECT @cols = COALESCE(@cols + ',', '') + QUOTENAME(subject)
FROM (SELECT DISTINCT subject FROM n881820_students_score WHERE stuid = 10002) s
-- 构建查询
SET @query = 'WITH a AS (
SELECT stuid, subject, score
FROM n881820_students_score
WHERE stuid = 10002
)
SELECT *
FROM a
PIVOT (
SUM(score) FOR subject IN (' + @cols + ')
) AS p
ORDER BY stuid'
-- 执行查询
EXECUTE(@query)
在上述代码中,我们使用 'SELECT DISTINCT
请注意,使用动态 SQL 时需要小心 SQL 注入攻击。在本例中,由于我们没有从外部参数中动态构建查询,因此不太可能受到注入攻击。但是,在其他情况下,您可能需要使用参数化查询来避免注入攻击。
解答二:
在Pivot中,IN子句需要指定常量值,而不能使用表达式或子查询。因此,您可以尝试使用动态SQL生成所需的列名,然后在Pivot中使用该列名列表。例如,可以使用以下查询:
DECLARE @cols AS NVARCHAR(MAX)
DECLARE @query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT distinct ',' + QUOTENAME(subject)
from n881820_students_score
where stuid = 10002
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'with a as (select stuid, subject, score from n881820_students_score where stuid = 10002)
select * from a
pivot (
sum(score) for subject in (' + @cols + ')
) as p order by stuid'
exec sp_executesql @query
这将动态生成列名列表,并在Pivot中使用它们。
以下情况推荐使用动态转换:
1、需要转置的列不确定,比如转置月的天数,月份的天数有28.29.30.31天,不确定
2、需要转置的列非常多时候,不方便一个个写
详情参考这个博文的方法,链接:https://www.cnblogs.com/Bokeyan/p/14447537.html
PIVOT 子句需要指定要进行列转行的列和新表的列名,这里的列名必须是固定的。如果不知道要转换的列有哪些值,可以先进行查询并动态生成列名,然后再构造 PIVOT 查询。
字段都存在一张表里面解决
PIVOT需要指定列值的名称,所以不能使用变量或子查询作为PIVOT子句中的列值。不过可以使用动态SQL来动态生成列值,从而实现行列转换。
在SQL中,PIVOT需要明确指定要转置的列,因此无法使用变量或子查询来替代。如果您不知道有哪些特定的值,可以先使用动态SQL生成查询语句,然后再执行查询。
以下是一个使用动态SQL的示例,可以将查询的结果动态地转置为所有不同的科目:
DECLARE @cols AS NVARCHAR(MAX), @query AS NVARCHAR(MAX)
-- 获取所有不同的科目,将其连接为逗号分隔的字符串
SELECT @cols = STUFF(
(SELECT DISTINCT ',[' + subject + ']'
FROM n881820_students_score
WHERE stuid = 10002
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),
1, 1, '')
-- 生成动态查询语句
SET @query = 'WITH a AS (
SELECT stuid, subject, score
FROM n881820_students_score
WHERE stuid = 10002
)
SELECT *
FROM a
PIVOT (
SUM(score) FOR subject IN (' + @cols + ')
) AS p
ORDER BY stuid'
-- 执行查询
EXECUTE(@query)
请注意,动态SQL可能存在SQL注入的风险,需要谨慎使用。