(1.3)DML增强功能-Apply、pivot、unpivot、for xml path行列转换
深入了解行列转换请参考另一篇文章:https://www.cnblogs.com/gered/p/9271581.html
总结:
1.apply一般形式

--基本形式
SELECT a FROM dbo.LargeTable AS LT--实际表
CROSS APPLY dbo.split(LT.Name,':')--自定义表值函数,处理以某个字符分隔的数据,把这些数据,返回一张表
WHERE a <> '' --去掉结果表中a字段为空的数据
2.pivot与unpivot一般形式
(1)pivot

(2)unpivot

--pivot基本形式
select *
from table
a pivot (max(行值) for 需要转换的列 in (转换值1,转换值2)) b --必须要别名否则报错
--unpivot基本形式
SELECT USERID,USERNO,tType=attribute
FROM (select * from tbl_列转行测试)a
UNPIVOT
(
转之后的值列名 FOR 转了之后的列所在列名 IN(列名A, 列名B,列名C)
) AS UPV --必须要别名否则报错
详情如下:
1.Apply
其分为两类CROSS APPLY和 OUTER APPLY
(1)CROSS APPLY
--基本形式
SELECT a FROM dbo.LargeTable AS LT--实际表
CROSS APPLY dbo.split(LT.Name,':')--自定义表值函数,处理以某个字符分隔的数据,把这些数据,返回一张表
WHERE a <> '' --去掉结果表中a字段为空的数据 --原理过程
--APPLY的执行过程,它先逻辑计算左表表达式(以上的LargeTable表),然后把右表达式(以上的自定义表值函数Split)应用到左表表达式的每一行。实际是把外部查询的列引用作为参数传递给表值函数。
--split函数
SELECT * FROM dbo.split('581::579::519::279::406::361::560',':')
ALTER Function [dbo].[Split](@Sql varchar(8000),@Splits varchar(10))
returns @temp Table (a varchar(100))
As
Begin
Declare @i Int
Set @Sql = RTrim(LTrim(@Sql))
Set @i = CharIndex(@Splits,@Sql)
While @i >= 1
Begin
Insert @temp Values(Left(@Sql,@i-1))
Set @Sql = SubString(@Sql,@i+1,Len(@Sql)-@i)
Set @i = CharIndex(@Splits,@Sql)
End
If @Sql <> ''
Insert @temp Values (@Sql)
Return
End
案例演示
【1】原始数据

【2】运行之后获得的数据

(2)OUTER APPLY
场景:有个供货商表(Supplier)和供货商产品表(Products),我们要取每一个供货商中单价最高的两个产品。
供货商表:
供货商产品表:
首先,我们创建一个自定义表值函数(dbo.fn_top_products),该函数根据供货商ID返回单价最高的两个商品。 好,前期的数据都已经准备好了,下面让我们试试用OUTER APPLY形式来查询,会出现什么结果。
- IF OBJECT_ID('dbo.fn_top_products') IS NOT NULL
- DROP FUNCTION dbo.fn_top_products;
- GO
--根据供货商ID获得单价最高的两件商品
- CREATE FUNCTION dbo.fn_top_products
- (@supid AS INT)
- RETURNS TABLE
- AS
- RETURN
- SELECT TOP(2)Id AS ProductId,ProductName,UnitPrice
- FROM dbo.Products
- WHERE SupplierId = @supid
- ORDER BY UnitPrice DESC
- GO
执行以下语句:
- SELECT S.id AS SupplierId,S.CompanyName,UnitPrice FROM dbo.Supplier AS S
- OUTER APPLY dbo.fn_top_products(S.id) AS P
执行结果如下:
注意最后为NULL的记录,reed公司因为没有商品,所以单价为NULL了。
如果用CROSS APPLY形式,执行以下查询:
- SELECT S.id AS SupplierId,S.CompanyName,UnitPrice FROM dbo.Supplier AS S
- CROSS APPLY dbo.fn_top_products(S.id) AS P
生成的输出结果如下:
大家看出OUTER APPLY和CROSS APPLY的区别了吧。
2.pivot 行转列
--基本形式
select *
from table
a pivot (max(行值) for 需要转换的列 in (转换值1,转换值2)) b
直接贴图吧:数据可以到另一篇文章去看https://www.cnblogs.com/gered/p/8696473.html

之所以很多地方为NULL是因为pivot和unpivot会把除 pivot()括号内的字段都作为分组项,所以如果想实现如下图效果。

则需要先做一个子查询或CTE来把相关字段给筛选出来,代码如下(或可以用case when做行转列直接group by 指定字段)
select *
from (select 学生姓名,成绩,课程名称 from tbl_Student)
a pivot (max(成绩) for 课程名称 in (语文,数学,英语,政治)) b
结果如下:

3.unpivot列转行
一般形式:
SELECT USERID,USERNO,tType=attribute
FROM (select * from tbl_列转行测试)a
UNPIVOT
(
转之后的值列名 FOR 转了之后的列所在列名 IN(列名A, 列名B,列名C)
) AS UPV --必须要别名否则报错
举例如下:

注意,这句话unpivot同样适用:之所以很多地方为NULL是因为pivot和unpivot会把除 pivot()括号内的字段都作为分组项
4.一个应用场景与FOR XML PATH应用
首先呢!我们在增加一张学生表,列分别为(stuID,sName,hobby),stuID代表学生编号,sName代表学生姓名,hobby列存学生的爱好!那么现在表结构如下:

这时,我们的要求是查询学生表,显示所有学生的爱好的结果集,代码如下:


SELECT sName,
(SELECT hobby+',' FROM student
WHERE sName=A.sName
FOR XML PATH('')) AS StuList
FROM student A
GROUP BY sName
) B


结果如下:
分析: 好的,那么我们来分析一下,首先看这句:
WHERE sName=A.sName
FOR XML PATH('')
这句是通过FOR XML PATH 将某一姓名如张三的爱好,显示成格式为:“ 爱好1,爱好2,爱好3,”的格式!
那么接着看:


SELECT sName,
(SELECT hobby+',' FROM student
WHERE sName=A.sName
FOR XML PATH('')) AS StuList
FROM student A
GROUP BY sName
) B


剩下的代码首先是将表分组,在执行FOR XML PATH 格式化,这时当还没有执行最外层的SELECT时查询出的结构为:

可以看到StuList列里面的数据都会多出一个逗号,这时随外层的语句:SELECT B.sName,LEFT(StuList,LEN(StuList)-1) as hobby 就是来去掉逗号,并赋予有意义的列明!
2.列转行

----------------------------------------------------------------
--> 测试数据[huang]if object_id('[huang]') is not null drop table [huang]go create table [huang]([a] nvarchar(4),[b] nvarchar(10))insert [huang]select 'X1','1,4,8' union allselect 'X2','2' union allselect 'X3','3,6' union allselect 'X4','7' union allselect 'X5','5'--------------生成数据--------------------------select
a.[a],
SUBSTRING(a.[b],number,CHARINDEX(',',[b]+',',b.number)-b.number) as [b] ,
b.number
from
[huang] a,master..spt_values b
where
b.number >=1 and b.number<=len(a.[b])
and b.type='p'
and substring(','+a.[b],b.number,1)=',' --演示代码
select * from master..spt_values
where type='p'
order by number
----------------结果----------------------------
(1.3)DML增强功能-Apply、pivot、unpivot、for xml path行列转换的更多相关文章
- (1.1)DML增强功能-CTE
1.CTE的通用形式 WITH temp_name as ( CTE查询结果集 ) 释义: (1)with/as :关键字 (2)temp_name:为CTE临时使用名称,可以看初学者做是一个临时表 ...
- (1.5)DML增强功能-try catch及事务控制
一.事务控制与Try Catch结合 当 SET XACT_ABORT 为 ON 时,如果执行 Transact-SQL 语句产生运行时错误,则整个事务将终止并回滚. 当 SET XACT_ABORT ...
- (1.4)DML增强功能-Output
Output在CRUD的区别 1.对于INSERT,可以引用inserted表以查询新行的属性.在insert into table output . 2.对于DELETE,可以引用deleted表以 ...
- (1.2)DML增强功能-4大排名函数与top ties/tablesample
关键字:sql server窗口函数.分析函数.四大窗口函数 1.row_number() over( partition by column order by column) (1)测试数据 (2 ...
- 12c分区增强功能,新功能(文档ID 1568010.1)
12c Partitioning Enhancements, New Features (Doc ID 1568010.1) APPLIES TO: Oracle Database - Enterpr ...
- SQL Server中行列转换 Pivot UnPivot
SQL Server中行列转换 Pivot UnPivot PIVOT用于将列值旋转为列名(即行转列),在SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT的一般语法是:PI ...
- SQL(横表和纵表)行列转换,PIVOT与UNPIVOT的区别和使用方法举例,合并列的例子
使用过SQL Server 2000的人都知道,要想实现行列转换,必须综合利用聚合函数和动态SQL,具体实现起来需要一定的技巧,而在SQL Server 2005中,使用新引进的关键字PIVOT/UN ...
- virtualbox安装增强功能时【未能加载虚拟光盘】
virtualbox安装增强功能时[未能加载虚拟光盘] 今天在使用Virtualbox中的Ubuntu虚拟机,想安装增强功能来实现更改分辨率,但是在安装时出错:未能加载虚拟光驱 VBoxsGuestA ...
- virtualbox安装增强功能(centos6.5)
vitualbox安装增强功能(centos 6.5) 1. 安装依赖包 #yum install kernel-headers-$(uname -r) #yum install kernel-dev ...
随机推荐
- 立即调用的函数表达式---IIFE
有些人则称为“自执行的匿名函数” 在闭包中,我们经常需要使用到匿名函数,我感觉闭包就是一种匿名函数,子集. 但是直接在匿名函数后面调用函数是会出错的.比如: function () { alert(& ...
- UVa 10450 - World Cup Noise
题目:构造一个01串,使得当中的1不相邻,问长度为n的串有多少中. 分析:数学,递推数列. 设长度为n的串有n个.则有递推关系:f(n)= f(n-1)+ f(n-2): 长度为n的结束可能是0或者1 ...
- 实例教程Unity3D单例模式(二)自我包括法
unity3d 里的单例模式自我包括法 有一次玩Trench Run game,我意识到我的场景类里存在很多的GameObject.所以,我开发了自我包括的单例.假设没找找到实例,就会创建它自己的Ga ...
- JBPM4.4_管理流程定义
1. 管理流程定义 没有更新功能 1.1. 部署流程定义 注意区分Deployment与ProcessDefinition 1.1.1. 示例代码1:流程定义有关文件在classpath中 Strin ...
- swift - UISegmentedControl 的用法
一.创建控件,并监听控件选择值 /*选项除了文字还可以是图片 as关键字的作用就是字面意思:类型转换*/ let items = ["选项一", "选项二", ...
- Android - Style问题
转自:http://jingyan.baidu.com/article/c910274be7536acd361d2dca.html 转自:http://blog.sina.com.cn/s/blog_ ...
- vue 组件库
iView https://www.iviewui.com/ Radon UI https://luojilab.github.io/radon-ui/#!/ Element http://eleme ...
- Linux 任务计划:crontab
(1) 什么是任务计划:也就是设置服务器在某个指定的时间执行某个指定的任务,比如执行一个命令,或执行一个脚本(2) Linux 使用 cron 服务来制定任务计划,cron 是服务名称,crond 是 ...
- Bash Shell 里的各种括号
天在 SegmentFault 上看到又有人问起关于Shell里各种括号的问题.对于很多玩Shell的人,括号是个很尴尬的问题,用起来没问题,说起来不明白,我在这里总结一下Bash Shell几种括号 ...
- Lua脚本和C++交互(二)
上一节讲了一些基本的Lua应用,下面,我要强调一下,Lua的栈的一些概念,因为这个确实很重要,你会经常用到.熟练使用Lua,最重要的就是要时刻知道什么时候栈里面的数据是什么顺序,都是什么.如果你能熟练 ...