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

0.背景说明

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) )
INSERT 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

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——透视PIVOT动态获取待扩展元素集的更多相关文章

  1. iwpriv工具通过ioctl动态获取相应无线网卡驱动的private_args所有扩展参数

    iwpriv工具通过ioctl动态获取相应无线网卡驱动的private_args所有扩展参数 iwpriv是处理下面的wlan_private_args的所有扩展命令,iwpriv的实现上,是这样的, ...

  2. SQL中PIVOT 行列转换

    来源:http://www.studyofnet.com/news/295.html PIVOT通过将表达式某一列中的唯一值转换为输出中的多个列来旋转表值表达式,并在必要时对最终输出中所需的任何其余列 ...

  3. map阶段动态获取CombineTextInputFormat各输入文件路径

    老mr程序中map中conf的map.input.file参数只能获取获取CombineTextInputFormat的第一个输入文件,而新版mr程序则连第一个输入文件也无法获取,这是因为create ...

  4. sql:pivot unpivot

    pivot  行转列 unpivot  列转行 源码跑步起来 这是能跑起来的 源码转自 http://www.cnblogs.com/zhangzt/archive/2010/07/29/178782 ...

  5. KTHREAD 线程调度 SDT TEB SEH shellcode中DLL模块机制动态获取 《寒江独钓》内核学习笔记(5)

    目录 . 相关阅读材料 . <加密与解密3> . [经典文章翻译]A_Crash_Course_on_the_Depths_of_Win32_Structured_Exception_Ha ...

  6. Delphi泛型动态数组的扩展--转贴

    此文章转载于http://www.raysoftware.cn/?p=278&tdsourcetag=s_pcqq_aiomsg的博客 从Delphi支持泛型的第一天起就有了一种新的动态数组类 ...

  7. MyBatis框架之SQL映射和动态SQL

    使用MyBatis实现条件查询 1.SQL映射文件: MyBatis真正的强大之处就在于SQL映射语句,MyBatis专注于SQL,对于开发人员来说也是极大限度的进行SQL调优,以保证性能.下面是SQ ...

  8. delphi 动态获取文件类型的图标

    delphi 动态获取文件类型的图标.txt我不奢望什么,只希望你以后的女人一个不如一个.真怀念小时候啊,天热的时候我也可以像男人一样光膀子!在应用程序的编写中,组合框(ComboBox).列表框(L ...

  9. js动态获取子复选项并设计全选及提交

    在做项目的时候,会遇到根据父选项,动态的获取子选项,并列出多个复选框,提交时,把选中的合并成一个字符提交后台 本章将讲述如何通过js控制实现该操作: 1:设计父类别为radio,为每一个radio都加 ...

随机推荐

  1. 基于mysql和Java Swing的简单课程设计

    摘要 现代化的酒店组织庞大.服务项目多.信息量大.要想提高效率.降低成本.提高服务质量和管理水平,进而促进经济效益,必须利用电脑网络技术处理宾馆酒店经营数据,实现酒店现代化的信息管理.本次课程设计运用 ...

  2. webpack4 插件ProvidePlugin使用遇到的问题

    根据博客https://www.cnblogs.com/geyouneihan/p/9769808.html学习webpack4中使用ProvidePlugin遇到了自定义js无法使用的问题,解决之后 ...

  3. docker PXC MYSQL集群节点启动失败/节点顺序消失/只剩一个节点存在问题的解决

    转载于:https://my.oschina.net/u/4884318/blog/4908669 大牛 佩服此人 截取本人遇到的问题: "error:0407008A:rsa routin ...

  4. 移动端常用单位——rem

    移动端常用单位: ①px:像素大小,固定值 ②%:百分比 ③em(不常用,但是在首行缩进时可以使用):相对自身的font大小(当自身的字体大小也是em做单位时,才会以父元素的字体大小为基准单位) ④r ...

  5. Linux基础——用户和用户组

    Linux基础--用户和用户组 一.用户和用户组 用户在/etc/passwd中 用户组在/etc/group/中注意:在创建用户时,系统默认生成一个用户组(组名和用户名一致) 1.用户 1.1查看用 ...

  6. Redis cluster的部署

    Redis 集群是一个提供在多个Redis间节点间共享数据的程序集. Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下 ...

  7. https(ssl) 免费证书

    https://letsencrypt.org/getting-started/ https://certbot.eff.org/lets-encrypt/centosrhel7-nginx http ...

  8. Mybatis-plus<三> MybatisPlus条件构造器

    Mybatis-plus<三> MybatisPlus条件构造器 Demo GitHub下载地址:https://github.com/RJvon/Mybatis_plus_demo My ...

  9. 剑指 Offer 38. 字符串的排列

    剑指 Offer 38. 字符串的排列 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素. 示例: 输入:s = "abc" ...

  10. noip模拟37

    \(\color{white}{\mathbb{燕子来时青尚在,木荫遥看杏花菲,名之以:杏红}}\) 考场发现 \(t2\) 基本上是原题,\(t3\) 的套路见过,\(t4\) 像是并查集之类的算法 ...