深入了解行列转换请参考另一篇文章: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形式来查询,会出现什么结果。

  1. IF OBJECT_ID('dbo.fn_top_products') IS NOT NULL
  2. DROP FUNCTION dbo.fn_top_products;
  3. GO

--根据供货商ID获得单价最高的两件商品

  1. CREATE FUNCTION dbo.fn_top_products
  2. (@supid AS INT)
  3. RETURNS TABLE
  4. AS
  5. RETURN
  6. SELECT TOP(2)Id AS ProductId,ProductName,UnitPrice
  7. FROM dbo.Products
  8. WHERE SupplierId = @supid
  9. ORDER BY UnitPrice DESC
  10. GO

  执行以下语句:

  1. SELECT S.id AS SupplierId,S.CompanyName,UnitPrice FROM dbo.Supplier AS S
  2. OUTER APPLY dbo.fn_top_products(S.id) AS P

  执行结果如下:

    

  注意最后为NULL的记录,reed公司因为没有商品,所以单价为NULL了。

  如果用CROSS APPLY形式,执行以下查询:

  1. SELECT S.id AS SupplierId,S.CompanyName,UnitPrice FROM dbo.Supplier AS S
  2. 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 B.sName,LEFT(StuList,LEN(StuList)-1) as hobby FROM (
SELECT sName,
(SELECT hobby+',' FROM student 
  WHERE sName=A.sName 
  FOR XML PATH('')) AS StuList
FROM student A 
GROUP BY sName
) B 

结果如下:

分析: 好的,那么我们来分析一下,首先看这句:

SELECT hobby+',' FROM student 
  WHERE sName=A.sName 
  FOR XML PATH('')

这句是通过FOR XML PATH 将某一姓名如张三的爱好,显示成格式为:“ 爱好1,爱好2,爱好3,”的格式!

那么接着看:

SELECT B.sName,LEFT(StuList,LEN(StuList)-1) as hobby FROM (
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 all
select 'X2','2' union all
select 'X3','3,6' union all
select 'X4','7' union all
select '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

 
----------------结果----------------------------

 
 
经典参考文章:https://blog.csdn.net/ml1990s/article/details/16953999
参考文章:https://www.cnblogs.com/doubleliang/archive/2011/07/06/2098775.html

    

(1.3)DML增强功能-Apply、pivot、unpivot、for xml path行列转换的更多相关文章

  1. (1.1)DML增强功能-CTE

    1.CTE的通用形式 WITH temp_name as ( CTE查询结果集 ) 释义: (1)with/as :关键字 (2)temp_name:为CTE临时使用名称,可以看初学者做是一个临时表 ...

  2. (1.5)DML增强功能-try catch及事务控制

    一.事务控制与Try Catch结合 当 SET XACT_ABORT 为 ON 时,如果执行 Transact-SQL 语句产生运行时错误,则整个事务将终止并回滚. 当 SET XACT_ABORT ...

  3. (1.4)DML增强功能-Output

    Output在CRUD的区别 1.对于INSERT,可以引用inserted表以查询新行的属性.在insert into table output . 2.对于DELETE,可以引用deleted表以 ...

  4. (1.2)DML增强功能-4大排名函数与top ties/tablesample

    关键字:sql server窗口函数.分析函数.四大窗口函数 1.row_number()  over( partition by column order by column) (1)测试数据 (2 ...

  5. 12c分区增强功能,新功能(文档ID 1568010.1)

    12c Partitioning Enhancements, New Features (Doc ID 1568010.1) APPLIES TO: Oracle Database - Enterpr ...

  6. SQL Server中行列转换 Pivot UnPivot

    SQL Server中行列转换 Pivot UnPivot PIVOT用于将列值旋转为列名(即行转列),在SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT的一般语法是:PI ...

  7. SQL(横表和纵表)行列转换,PIVOT与UNPIVOT的区别和使用方法举例,合并列的例子

    使用过SQL Server 2000的人都知道,要想实现行列转换,必须综合利用聚合函数和动态SQL,具体实现起来需要一定的技巧,而在SQL Server 2005中,使用新引进的关键字PIVOT/UN ...

  8. virtualbox安装增强功能时【未能加载虚拟光盘】

    virtualbox安装增强功能时[未能加载虚拟光盘] 今天在使用Virtualbox中的Ubuntu虚拟机,想安装增强功能来实现更改分辨率,但是在安装时出错:未能加载虚拟光驱 VBoxsGuestA ...

  9. virtualbox安装增强功能(centos6.5)

    vitualbox安装增强功能(centos 6.5) 1. 安装依赖包 #yum install kernel-headers-$(uname -r) #yum install kernel-dev ...

随机推荐

  1. 立即调用的函数表达式---IIFE

    有些人则称为“自执行的匿名函数” 在闭包中,我们经常需要使用到匿名函数,我感觉闭包就是一种匿名函数,子集. 但是直接在匿名函数后面调用函数是会出错的.比如: function () { alert(& ...

  2. UVa 10450 - World Cup Noise

    题目:构造一个01串,使得当中的1不相邻,问长度为n的串有多少中. 分析:数学,递推数列. 设长度为n的串有n个.则有递推关系:f(n)= f(n-1)+ f(n-2): 长度为n的结束可能是0或者1 ...

  3. 实例教程Unity3D单例模式(二)自我包括法

    unity3d 里的单例模式自我包括法 有一次玩Trench Run game,我意识到我的场景类里存在很多的GameObject.所以,我开发了自我包括的单例.假设没找找到实例,就会创建它自己的Ga ...

  4. JBPM4.4_管理流程定义

    1. 管理流程定义 没有更新功能 1.1. 部署流程定义 注意区分Deployment与ProcessDefinition 1.1.1. 示例代码1:流程定义有关文件在classpath中 Strin ...

  5. swift - UISegmentedControl 的用法

    一.创建控件,并监听控件选择值 /*选项除了文字还可以是图片 as关键字的作用就是字面意思:类型转换*/ let items = ["选项一", "选项二", ...

  6. Android - Style问题

    转自:http://jingyan.baidu.com/article/c910274be7536acd361d2dca.html 转自:http://blog.sina.com.cn/s/blog_ ...

  7. vue 组件库

    iView https://www.iviewui.com/ Radon UI https://luojilab.github.io/radon-ui/#!/ Element http://eleme ...

  8. Linux 任务计划:crontab

    (1) 什么是任务计划:也就是设置服务器在某个指定的时间执行某个指定的任务,比如执行一个命令,或执行一个脚本(2) Linux 使用 cron 服务来制定任务计划,cron 是服务名称,crond 是 ...

  9. Bash Shell 里的各种括号

    天在 SegmentFault 上看到又有人问起关于Shell里各种括号的问题.对于很多玩Shell的人,括号是个很尴尬的问题,用起来没问题,说起来不明白,我在这里总结一下Bash Shell几种括号 ...

  10. Lua脚本和C++交互(二)

    上一节讲了一些基本的Lua应用,下面,我要强调一下,Lua的栈的一些概念,因为这个确实很重要,你会经常用到.熟练使用Lua,最重要的就是要时刻知道什么时候栈里面的数据是什么顺序,都是什么.如果你能熟练 ...