您的位置:首页 > 数据库

T-SQL——透视PIVOT动态获取待扩展元素集

2021-10-08 01:00 232 查看 https://www.cnblogs.com/shanzh

目录

志铭-2021年10月8日 00:57:00

0.背景说明

在< 56c a href="https://www.cnblogs.com/shanzhiming/p/15371249.html" target="_blank">T-SQL——数据透视和逆透视文中介绍了透视和逆透视

使用

PIVOT
对结果集进行数据透视

SELECT FROM Table PIVOT(任意聚合函数(聚合字段)  FOR 待扩展字段名 IN (待扩展元素集)) AS T

其中的 待扩展元素集需要一个静态列表

简单的说:

IN(待扩展元素集)
,是不支持动态的子查询

即不能这样写

IN (select 带扩展元素 from table)

所以带扩展元素集需要我们就直接罗列出来即可

SELECT * FROM PIVOT(SUN(Scores) FOR Subject IN (语文,数学,外语))

若是实际开发中,需要动态的 查询待扩展元素集

这就需要我们使用动态SQL取构建查询语句,并执行查询


1.准备测试数据

  • 学生成绩表
----学生成绩表
IF OBJECT_ID('tempdb..#tempStudent') IS NOT NULL
BEGIN
DROP TABLE #tempStudent
END
CREATE TABLE #tempStudent
(
[Name] varchar(4),
[SubjectName] varchar(4),
[Scores] int,
[Class] varchar(10) )
INSER
ad0
T INTO #tempStudent
VALUES
( '张三', '语文', 100, '八年级一班' ),
( '张三', '数学', 90, '三年级二班' ),
( '张三', '英语', 80, '三年级二班' ),
( '李四', '语文', 90, '三年级二班' ),
( '李四', '数学', 70, '三年级二班' ),
( '李四', '英语', 60, '三年级二班' )
  • 考试科目表
----学生科目表
IF OBJECT_ID('tempdb..#tempSubject') IS NOT NULL
BEGIN
DROP TABLE #tempSubject;
END;

CREATE TABLE #tempSubject
(
[SubjectName] VARCHAR(4)
);
INSERT INTO #tempSubject
VALUES
('语文'),
('数学'),
('英语');

2.示例1——利用SELECT循环赋值

这里假定我们有单独的待扩展元素集的表,比如说这里我们有独立的课程名称表#tempSubject
所以我们可以单独的查询后拼接出静态的待扩展元素集

----拼接待扩展元素集
DECLARE @subjectStr VARCHAR(100)='';--注意一定要初始化为空字符串,才能实现下面的累加
SELECT @subjectStr=@subjectStr+SubjectName+',' FROM #tempSubject--拼接扩展元素集
SET @subjectStr	=LEFT(@subjectStr,len(@subjectStr)-1)--删除拼接的最后一个逗号
SELECT @subjectStr--返回:语文,数学,英语

----将透视SQL语句定义为字符串,并执行
DECLARE @sql NVARCHAR(1000) = 'SELECT * FROM  #tempStudent PIVOT(SUM(Scores)  FOR [SubjectName] IN ({@subjectStr}))T';--使用“{@subjectStr}”做占位符
SET @sql = REPLACE(@sql, '{@subjectStr}', @subjectStr);--替换占位符

SELECT @sql;
EXEC sp_executesql @sql;

-- 结果
-- Name Class      语文          数学          英语
-- ---- ---------- ----------- ----------- -----------
-- 张三   八年级一班      100         NULL        NULL
-- 李四   三年级二班      90          70          60
-- 张三   三年级二班      NULL        90          80

假设我们没有单独维护待扩展元素集的数据表,即这里没有提供#tempSubjcet
我看可以直接去重查询后#tempStudent中的SubjectName字段值,进行拼接

----拼接待扩展元素集
DECLARE @subjectStr VARCHAR(100) = '';
WITH cteSubject
AS
(
SELECT DISTINCT SubjectName FROM #tempStudent
)
SELECT @subjectStr = @subjectStr + SubjectName + ',' FROM cteSubject; --拼接扩展元素集
SET @subjectStr = LEFT(@subjectStr, LEN(@subjectStr) - 1); --删除拼接的最后一个逗号
SELECT @subjectStr; --返回:语文,数学,英语

--……后续操作如示例1
200a

3.示例2——使用游标

  • 若是有必要的话,可以使用游标拼接待扩展元素集
DECLARE @sql NVARCHAR(1000),
@subjectStr VARCHAR(1000),
@first INT;

--创建游标
DECLARE curStudent CURSOR FAST_FORWARD FOR
SELECT DISTINCT SubjectName FROM #tempStudent;

SET @first = 1;--标志变量:用于区分是否是第一个拼接字符串
SET @sql = N'SELECT * FROM  #tempStudent PIVOT(SUM(Scores)  FOR [SubjectName] IN (';

OPEN curStudent;
FETCH NEXT FROM curStudent INTO @subjectStr;
WHILE @@fetch_status = 0
BEGIN
IF @first = 0
SET @sql = @sql + N',';
ELSE
SET @first = 0;

SET @sql = @sql + @subjectStr;

FETCH NEXT FROM curStudent INTO @subjectStr;
END;
CLOSE curStudent;
DEALLOCATE curStudent;

SET @sql = @sql + N')) AS T;';

EXEC sp_executesql @sql;

4.示例3——使用FOR XML PATH()

其实针对构造"value1,value2,value3"格式的字符串,使用

FOR XML PATH()
函数配合
STUFF()
函数,是极其的方便

DECLARE @subjectStr VARCHAR(100);

WITH cteStudent AS
(
SELECT DISTINCT SubjectName FROM  #tempStudent
)
SELECT @subjectStr= STUFF((SELECT ',' + SubjectName FROM cteStudent FOR XML PATH('')),1,1,'')
--这里@subjectStr=数学、英语、语文

DECLARE @sql NVARCHAR(1000) = 'SELECT * FROM  #tempStudent PIVOT(SUM(Scores)  FOR [SubjectName] IN ({@subjectStr}))T';--使用“{@subjectStr}”做占位符
SET @sql = REPLACE(@sql, '{@subjectStr}', @subjectStr);--替换占位符

SELECT @sql;
EXEC sp_executesql @sql;

5. 参考

  • T-SQL——动态SQL
  • T-SQL——基础语法
  • T-SQL——游标
  • T-SQL——XML
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: