关于UNPIVOT 操作符
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。并联使用操作符的作用是为了转换两组列。这样讲能表示为一个参数名称和值在一行里面。执行代码如下:
通过这个输出结果,能发现不同的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 操作符的更多相关文章
- SQL Server的事务处理与高级查询
6.高级查询与脚本 6.1子查询 位于SELECT查询中的SELECT查询. 6.11 标量表达式 select id,val,val-(select avg(val) from tbltest) f ...
- KingbaseES 的行列转换
目录 背景 行转列 数据准备 分组聚合函数+CASE 根据压缩数据的格式,横向展开数据列选取不同方式 crosstab函数 PIVOT 操作符 PIVOT 操作符的限制 工具 ksql 的元命令 \c ...
- Oracle 的基本操作符
!= 不等于 select empno,ename,job from scott.emp where job!='manager' ^= 不等于 select empno,ename,job from ...
- Pivot 和 Unpivot
在TSQL中,使用Pivot和Unpivot运算符将一个关系表转换成另外一个关系表,两个命令实现的操作是“相反”的,但是,pivot之后,不能通过unpivot将数据还原.这两个运算符的操作数比较复杂 ...
- javascript中的操作符详解1
好久没有写点什么了,根据博主的技术,仍然写一点javascript新手入门文章,接下来我们一起来探讨javascript的操作符. 一.前言 javascript中有许多操作符,但是许多初学者并不理解 ...
- c# 基础 object ,new操作符,类型转换
参考页面: http://www.yuanjiaocheng.net/webapi/config-webapi.html http://www.yuanjiaocheng.net/webapi/web ...
- oracle操作符
Oracle中算术操作符(+)(-)(*)(/) 值得注意的是:/ 在oracle中就相当于显示中的除法 5/2 = 2.5 比较操作符: 其中等号可以换成其他运算符:(后面为该操作符的单条件查询样例 ...
- C# 本质论 第三章 操作符和控制流
操作符通常分为3大类:一元操作符(正.负).二元操作符(加.减.乘.除.取余)和三元操作符( condition?consequence:alternative(consequence和alterna ...
- SQL优化技术分析-1:操作符优化
1.IN 操作符 用IN写出来的SQL的优点是比较容易写及清晰易懂,这比较适合现代软件开发的风格.但是用IN的SQL 性能总是比较低的,从Oracle执行的步骤来分析用IN的SQL与不用IN的SQL有 ...
随机推荐
- EF6 中tracking log使用方法总结
先上一段最近项目中的代码,此代码可以放到自己项目中的dbContext中 public override Task<int> SaveChangesAsync() { List<Au ...
- Eclipse导入Java项目时“No projects are found to import”错误的处理
用Eclipse导入Java项目时,经常会出现“No projects are found to import”错误(尤其是导入网上下载的项目时),这是因为文件夹里面没有.project和.class ...
- 自行实现PHP代码注解特性
PHP 注解 到目前为止,PHP的反射特性中是不支持注解Annotation的,但是可以支持基本的文档注释内容的获取 ReflectionMethod::getDocComment() - 从5.1. ...
- [PHP] 使用Socket提供Http服务
我的SimpleLoader里面的一块 https://github.com/taoshihan1991/simpleloader <?php namespace Server; class S ...
- FileIputeStream用于读写文件,并且用字节的方式表示出来
package com.Java; import java.io.FileInputStream; import java.io.FileNotFoundException; import java. ...
- php自动载入类的实践
<?php //function __autoload($class_name) {// require_once $class_name . '.php';//} spl_autoloa ...
- 2016读书List
2016年读书书单. 1. <华尔街漫步> + <战胜华尔街>+ <华尔街之狼> 2. <野蛮大陆> 3. <第三帝国的最后十四天> 4. ...
- Android填坑系列:Android JSONObject 中对key-value为null的特殊处理
在与服务端通过JSON格式进行交互过程中,不同版本的JSON库在对于key-value为null情况上的处理不同. Android自带的org.json对key-value都要求不能为null,对于必 ...
- GJM:用C#实现网络爬虫(二) [转载]
上一篇<用C#实现网络爬虫(一)>我们实现了网络通信的部分,接下来继续讨论爬虫的实现 3. 保存页面文件 这一部分可简单可复杂,如果只要简单地把HTML代码全部保存下来的话,直接存文件就行 ...
- 管理系统-------------SSH框架书写登录和显示用户
一.思路的穿插. web.xml中的配置找到--->application.xml---->找到对应的Action---->找到struts.xml----->在去找actio ...