UNPIVOT 操作符说明

简而言之,UNPIVOT操作符就是取得一个行的数据集合,然后把每一行都转换成多个行数据。为了更好地理解,请看下图:

图1

从上图中,你能发现UNPOVOT操作符,取得了两行数据,每行包含三个Price值,然后将这些转化成6行数据,其中每个产品价格都是一个不同的行。

UNPIVOT 命令制定了两个不同的列类型。第一个类型是列中不被转换的。在例子中,ID、产品名字列是这样的列类型。第二种列类型就是那些被转换的。诸如ProductCode, Wholesale 和Retail 这三列。在我上面的例子中,那些没有被转换的列将被在每套列值集合中重复,而另外的那些列将被转换成行。

UNPIVOT 语法

下面就是 UNPIVOT 的语法:

SELECT [columns not unpivoted],
[unpivot_column],
[value_column],
FROM
(<source query>)
AS <alias for the source data>
UNPIVOT ( [value_column] FOR [unpivot_column] IN ( <column_list> ) )
AS <alias for unpivot>

Where:

    • [columns not unpivoted]: 不被转换的列的名字清单。
    • [unpivot_column]: 不转换的列的名称。
    • [value_column]: 确定一个列名称来代表不转换的列的数据。
    • <source query>: 源数据。
  •       <alias for the source data>: 为源数据转换后的表确定一个别名。
  •       <column_list>:  被转换的列的列名称。
  •      <alias for unpivot>: 为转换操作的整套生产,确定一个别名。

为了更好地理解我们看下面的例子:

简单的例子

USE tempdb;
GO
IF object_id('PhoneNumbers') IS NOT NULL DROP TABLE PhoneNumbers;
GO
CREATE TABLE PhoneNumbers (
PersonID int,
HomePhone varchar(12),
CellPhone varchar(12),
Workphone varchar(12),
FaxNumber varchar(12)); INSERT INTO PhoneNumbers VALUES
(1,Null,'444-555-2931',Null,Null),
(2,'444-555-1950','444-555-2931',Null, Null),
(3,'444-555-1950', Null,'444-555-1324','444-555-2310'),
(4,'444-555-1950','444-555-2931','444-555-1324',
'444-555-1987');

Listing 1: 创建并填充PhoneNumbers 数据

SELECT PersonID, PhoneType, PhoneNumber
FROM (
SELECT PersonID, HomePhone, CellPhone, Workphone, FaxNumber
FROM PhoneNumbers ) AS Src
UNPIVOT (
PhoneNumber FOR PhoneType IN
(HomePhone, CellPhone, WorkPhone, FaxNumber)) AS UNPVT;

Listing 2: 行列转换语法例子

执行上面代码后显示如下图:

通过这个例子,我们发现执行结果中每行数据只包含一个单一的电话号码,同时注意到结果中在原表中有几个号码不为null则有几行数据,ID也就有几次。接下来我们进一步通过使用UNPIVOT来加深认识。

使用两个UNPIVOT操作符

第二个例子中,我将使用两个操作符来行转列来转换一套名字/值 的两列数据。具体如下:

在表 CustPref里面 我有四对名称和值。

我们将使用不同的UNPIVOT操作符来创建一个结果集,每一个PrefType的名字和值针对每个CustID 和CustName。并联使用操作符的作用是为了转换两组列。这样讲能表示为一个参数名称和值在一行里面。执行代码如下:

http://www.cnblogs.com/wenBlog/

通过这个输出结果,能发现不同的type对应不同的值得列,并且要关联CustID。整个查询通过两个不同的UNPOVOT操作符同时使用了where 子句来合并输出结果(基于列名前五个字符相同的进行匹配),第一个行转列转换的是数据,第二个为类型,where限制了比较前五个字符,我能取得匹配的数据组。

动态UNPIVOT查询

代码如下:

USE tempdb;
GO
DECLARE @ColNames varchar(1000);
SET @ColNames = '';
-- Get PrefValue Columns
SELECT @ColNames=stuff((
SELECT DISTINCT ',' + QUOTENAME(COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS p2
WHERE TABLE_NAME = 'CustPref'
AND COLUMN_NAME like 'Pref_Type'
FOR XML PATH(''), TYPE).value('.', 'varchar(max)')
,1,1,'')
-- Get PrefType Columns
DECLARE @ColValues varchar(1000);
SET @ColValues = '';
SELECT @ColValues=stuff((
SELECT DISTINCT ',' + QUOTENAME(COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS p2
WHERE TABLE_NAME = 'CustPref'
AND COLUMN_NAME like 'Pref_Data'
FOR XML PATH(''), TYPE).value('.', 'varchar(max)')
,1,1,'')
-- Generate UNPIVOT Statement
DECLARE @CMD nvarchar(2000);
SET @CMD = 'SELECT CustId, CustName, PrefType, PrefValue FROM ' +
'(SELECT CustID, CustName, ' + @ColNames + ',' + @ColValues +
' FROM CustPref) AS Perf UNPIVOT (PrefValue FOR PrefValues IN (' +
@ColValues + ')) AS UP1 UNPIVOT (PrefType FOR PrefTypes IN (' +
@ColNames + ')) AS UP2 WHERE ' +
'substring(PrefValues,5,1) = substring(PrefTypes,5,1);'
-- Print UNPIVOT Command
PRINT @CMD
-- Execute UNPIVOT Command
execute sp_executesql @CMD

结果是与上面的例子完全相同的。

为了完成和这个动态的SQL,我使用了INFORMATION_SCHEMA.COLUMNS视图。这个视图能帮我们设定两个变量@ColNames和@ColValues ,这就包含了用逗号区分的列名的字符串。这两个变量被用来构建动态的行转列查询。一旦我建立了动态的SQL就能,执行这个sp_executesql了。

这是一个简单的实例,但是相同的逻辑可以应用于更多的不同的组列的转换。

Summary

UNPIVOT操作符在2005 首次被引入,允许我们将多个name/value 列从不规范的表中创建到一个规范画的结果集中,并且一一对应于选定的列。通过使用这个操作符,我们能同时转换多个不同组的name/value 的成对的列。

关于UNPIVOT 操作符的更多相关文章

  1. SQL Server的事务处理与高级查询

    6.高级查询与脚本 6.1子查询 位于SELECT查询中的SELECT查询. 6.11 标量表达式 select id,val,val-(select avg(val) from tbltest) f ...

  2. KingbaseES 的行列转换

    目录 背景 行转列 数据准备 分组聚合函数+CASE 根据压缩数据的格式,横向展开数据列选取不同方式 crosstab函数 PIVOT 操作符 PIVOT 操作符的限制 工具 ksql 的元命令 \c ...

  3. Oracle 的基本操作符

    != 不等于 select empno,ename,job from scott.emp where job!='manager' ^= 不等于 select empno,ename,job from ...

  4. Pivot 和 Unpivot

    在TSQL中,使用Pivot和Unpivot运算符将一个关系表转换成另外一个关系表,两个命令实现的操作是“相反”的,但是,pivot之后,不能通过unpivot将数据还原.这两个运算符的操作数比较复杂 ...

  5. javascript中的操作符详解1

    好久没有写点什么了,根据博主的技术,仍然写一点javascript新手入门文章,接下来我们一起来探讨javascript的操作符. 一.前言 javascript中有许多操作符,但是许多初学者并不理解 ...

  6. c# 基础 object ,new操作符,类型转换

    参考页面: http://www.yuanjiaocheng.net/webapi/config-webapi.html http://www.yuanjiaocheng.net/webapi/web ...

  7. oracle操作符

    Oracle中算术操作符(+)(-)(*)(/) 值得注意的是:/ 在oracle中就相当于显示中的除法 5/2 = 2.5 比较操作符: 其中等号可以换成其他运算符:(后面为该操作符的单条件查询样例 ...

  8. C# 本质论 第三章 操作符和控制流

    操作符通常分为3大类:一元操作符(正.负).二元操作符(加.减.乘.除.取余)和三元操作符( condition?consequence:alternative(consequence和alterna ...

  9. SQL优化技术分析-1:操作符优化

    1.IN 操作符 用IN写出来的SQL的优点是比较容易写及清晰易懂,这比较适合现代软件开发的风格.但是用IN的SQL 性能总是比较低的,从Oracle执行的步骤来分析用IN的SQL与不用IN的SQL有 ...

随机推荐

  1. LeetCode4:Add Two Numbers

    题目: You are given two linked lists representing two non-negative numbers. The digits are stored in r ...

  2. PHP团队编码质量提升之道

    这段文字其实只是标题党. 目前PHP猿的薪资水平普遍较高,但其实绝大多数PHP猿都不是科班出身,你问一个什么是OOP的问题可能都说不清楚. 在团队中,除了费力的去普及编程语言的基础知识,要想提高开发质 ...

  3. Scalaz(29)- Free :Coyoneda - Functor for free

    很多时候我们会遇到一些高阶类型F[_],但又无法实现它的map函数,也就是虽然形似但F不可能成为Functor.看看下面的例子: trait Interact[A] case class Ask(pr ...

  4. java 克隆

    1. About Java中, 对于基本数据类型可以使用"=" 来克隆,此时两个对象除了相等是没有任何关系的; 而对于引用类型, 却不能简单地使用"="来克隆, ...

  5. Release编译模式下,事件是否会引起内存泄漏问题初步研究

    题记:不常发生的事件内存泄漏现象 想必有些朋友也常常使用事件,但是很少解除事件挂钩,程序也没有听说过内存泄漏之类的问题.幸运的是,在某些情况下,的确不会出问题,很多年前做的项目就跑得好好的,包括我也是 ...

  6. Microsoft SQL Server Compact 4.0&&ADO.NET Entity Framework 4.1&&MVC3

    最近重新查看微软MvcMusicStore-v3.0的源代码,发现忽略了很多重要的东西,特别是数据访问那一部分. 首先Microsoft SQL Server Compact 4.0 详细的介绍和下载 ...

  7. QRCode.js 生成二维码

    QRCode.js 是一个用于生成二维码图片的插件. github地址 在线实例 实例预览 基础示例 实例预览 API 接口 使用方法 载入 JavaScript 文件 <script src= ...

  8. 学习 Mobile App 网站制作的11个优秀案例

    我喜欢收集美丽的,精心设计的移动应用程序网站.在我看来,为 App 提供一个美丽的网站显示了设计者和开发者对它的用户和产品的关心,除了开发应用程序,他们去加倍努力去促进应用和传播关于它的 App. 我 ...

  9. React Canvas:高性能渲染 React 组

    React Canvas 提供了使用 Canvas 渲染移动 Web App 界面的能力,替代传统的 DOM 渲染,具有更接近 Native App 的使用体验.React Canvas 提供了一组标 ...

  10. jQuery立体式数字动态增加(animate方法)

    1.HTML结构 <div class="integral">已有<span class="ii"></span>积分< ...