志铭-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. 多台服务器共享session问题(2)

    多台服务器共享session问题  转载自:https://www.cnblogs.com/lingshao/p/5580287.html 在现在的大型网站中,如何实现多台服务器中的session数据 ...

  2. Linux从头学09:x86 处理器如何进行-层层的内存保护?

    作 者:道哥,10+年的嵌入式开发老兵. 公众号:[IOT物联网小镇],专注于:C/C++.Linux操作系统.应用程序设计.物联网.单片机和嵌入式开发等领域. 公众号回复[书籍],获取 Linux. ...

  3. 轻松搞定webpack5.x

    源码地址:https://gitee.com/cyp926/webpack-project.git "webpack": "^5.46.0", "we ...

  4. 微信小程序 转盘抽奖 倒计时 整点

    xml: <view id="luckdraw_box"> <view id="luckdraw_back"> <image st ...

  5. Learning ROS: Getting started with roswtf (检查ROS系统,找出问题)

    本文主要部分来源于ROS官网的Tutorials. roswtf是ROS的检查工具,用于检查ROS安装和运行系统. Checking your installation&Offline mak ...

  6. 【转】Linux 查看端口占用情况

    Linux 查看端口占用情况可以使用 lsof 和 netstat 命令. lsof lsof(list open files)是一个列出当前系统打开文件的工具. lsof 查看端口占用语法格式: l ...

  7. vue随记

    (一)使用props传值: <HeadTitle name-data="100"></HeadTitle> props:['nameData'] 父组件传递 ...

  8. [Navicat15 试用期过期解决办法]

    Navicat15 试用期过期解决办法 第一步:关闭Navicat 第二步: 打开注册表编辑器,win + R, 输入regedit 第三步: 在最上方搜索框输入HKEY_CURRENT_USER\S ...

  9. PHP的那些魔术方法(二)

    上文中介绍了非常常用并且也是面试时的热门魔术方法,而这篇文章中的所介绍的或许并不是那么常用,但绝对是加分项.当你能准确地说出这些方法及作用的时候,相信对方更能对你刮目相看. __sleep()与__w ...

  10. Mixed Content: The page at 'xxx' was loaded over HTTPS, but requested an insecure resource 'xxx'.

    HTTPS页面里动态的引入HTTP资源,比如引入一个js文件,会被直接block掉的.在HTTPS页面里通过AJAX的方式请求HTTP资源,也会被直接block掉的. Mixed Content: T ...