深入了解行列转换请参考另一篇文章: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. apache Storm之一-入门学习

    准备工作 这个教程使用storm-starter项目里面的例子.我推荐你们下载这个项目的代码并且跟着教程一起做.先读一下:配置storm开发环境和新建一个strom项目这两篇文章把你的机器设置好. 一 ...

  2. 在Delphi中编写res文件

    delphiimagedosinterfaceborland脚本先用记事本编写一个rc的文件. 如内容为: _Comms RCData Comms.jpg Comms.jpg为图片名称, 然后在这个r ...

  3. HEVC compressGOP 接口

    HEVC编码调用compressGOP()来实现一个GOPSize 图像序列的编码.在reference code里,真正做compressGOP编码之前,需要存GOPSize帧YUV在m_cList ...

  4. C#获取CPU处理器核心数量的方法_C#教程

    https://yq.aliyun.com/ziliao/89096 摘要: 本文讲的是C#获取CPU处理器核心数量的方法_C#教程, 有几条不同的处理器信息,您可以获得有关的信息:物理处理器数量.核 ...

  5. GIS-005-Dojo & jQuery 事件处理

    1.添加事件 dojo.connect(dojo.byId("SelectRect"), "onclick", function () { //todo }); ...

  6. Hash表 hash table 又名散列表

    直接进去主题好了. 什么是哈希表? 哈希表(Hash table,也叫散列表),是根据key而直接进行访问的数据结构.也就是说,它通过把key映射到表中一个位置来访问记录,以加快查找的速度.这个映射函 ...

  7. 实例:用类来写一个 memcached 启动脚本

    [root@localhost ~]$ yum install -y memcached #!/usr/bin/env python #-*- coding:utf-8 -*- import os i ...

  8. 最简单的VS-Qt-CMake项目框架

    使用qtcreator新建一个空工程,可以得到main.cpp,mainwindow.cpp,mainwindow.h和mainwindow.ui四个文件 下面主要介绍CMakeLists.txt的内 ...

  9. Objective-c官方文档翻译 类的定义

     类是对象的蓝图. 一个类是描述了对象的行为和属性.例如NSString的一个实例.他的类提供了各种的方法来转化和表示他的内部字符的表示.   每个类的实例都包含了这个类的属性和行为.例如每个NSSt ...

  10. 日记整理---->2016-11-23

    这里放一些jquery的学习知识.可能从一开始就是我一个人单枪匹马,来年不求并肩作战,只愿所向披靡. jquery的学习一 jquery关于ajax的一些学习博客 ajax方法的介绍:https:// ...