重温SQL——行转列,列转行(转:http://www.cnblogs.com/kerrycode/archive/2010/07/28/1786547.html)...

行转列,列转行是我们在开发过程中经常碰到的问题。行转列一般通过CASE WHEN 语句来实现,也可以通过 SQL SERVER 2005 新增的运算符PIVOT来实现。 用传统的方法,比较好理解。层次清晰,而且比较习惯。 但是PIVOT 、UNPIVOT提供的语法比一系列复杂的 SELECT...CASE 语句中所指定的语法更简单、更具可读性。下面我们通过几个简单的例子来介绍一下列转行、行转列问题。

我们首先先通过一个老生常谈的例子,学生成绩表(下面简化了些)来形象了解下行转列 

ExpandedBlockStart.gif代码
CREATE  TABLE [StudentScores]
(
    
[UserName]         NVARCHAR(20),        --学生姓名
    [Subject]          NVARCHAR(30),        --科目
    [Score]            FLOAT,               --成绩
)

INSERT INTO [StudentScores] SELECT 'Nick''语文'80

INSERT INTO [StudentScores] SELECT 'Nick''数学'90

INSERT INTO [StudentScores] SELECT 'Nick''英语'70

INSERT INTO [StudentScores] SELECT 'Nick''生物'85

INSERT INTO [StudentScores] SELECT 'Kent''语文'80

INSERT INTO [StudentScores] SELECT 'Kent''数学'90

INSERT INTO [StudentScores] SELECT 'Kent''英语'70

INSERT INTO [StudentScores] SELECT 'Kent''生物'85

 

 如果我想知道每位学生的每科成绩,而且每个学生的全部成绩排成一行,这样方便我查看、统计,导出数据

ExpandedBlockStart.gif代码
SELECT 
      UserName, 
      
MAX(CASE Subject WHEN '语文' THEN Score ELSE 0 ENDAS '语文',
      
MAX(CASE Subject WHEN '数学' THEN Score ELSE 0 ENDAS '数学',
      
MAX(CASE Subject WHEN '英语' THEN Score ELSE 0 ENDAS '英语',
      
MAX(CASE Subject WHEN '生物' THEN Score ELSE 0 ENDAS '生物'
FROM dbo.[StudentScores]
GROUP BY UserName

查询结果如图所示,这样我们就能很清楚的了解每位学生所有的成绩了

 

 

接下来我们来看看第二个小列子。有一个游戏玩家充值表(仅仅为了说明,举的一个小例子),

 ExpandedBlockStart.gif代码

CREATE TABLE [Inpours]
(
    
[ID]             INT IDENTITY(1,1), 
    
[UserName]          NVARCHAR(20),  --游戏玩家
    [CreateTime]     DATETIME,      --充值时间    
    [PayType]         NVARCHAR(20),  --充值类型    
    [Money]             DECIMAL,       --充值金额
    [IsSuccess]         BIT,           --是否成功 1表示成功, 0表示失败
    CONSTRAINT [PK_Inpours_ID] PRIMARY KEY(ID)
)

INSERT INTO Inpours SELECT '张三''2010-05-01''支付宝'501

INSERT INTO Inpours SELECT '张三''2010-06-14''支付宝'501

INSERT INTO Inpours SELECT '张三''2010-06-14''手机短信'1001

INSERT INTO Inpours SELECT '李四''2010-06-14''手机短信'1001

INSERT INTO Inpours SELECT '李四''2010-07-14''支付宝'1001

INSERT INTO Inpours SELECT '王五''2010-07-14''工商银行卡'1001

INSERT INTO Inpours SELECT '赵六''2010-07-14''建设银行卡'1001

 


下面来了一个统计数据的需求,要求按日期、支付方式来统计充值金额信息。这也是一个典型的行转列的例子。我们可以通过下面的脚本来达到目的
ExpandedBlockStart.gif代码
SELECT CONVERT(VARCHAR(10), CreateTime, 120AS CreateTime,
       
CASE PayType WHEN '支付宝'     THEN SUM(MoneyELSE 0 END AS '支付宝',
       
CASE PayType WHEN '手机短信'    THEN SUM(MoneyELSE 0 END AS '手机短信',
       
CASE PayType WHEN '工商银行卡'  THEN SUM(MoneyELSE 0 END AS '工商银行卡',
       
CASE PayType WHEN '建设银行卡'  THEN SUM(MoneyELSE 0 END AS '建设银行卡'
FROM Inpours
GROUP BY CreateTime, PayType

 

 如图所示,我们这样只是得到了这样的输出结果,还需进一步处理,才能得到想要的结果

ExpandedBlockStart.gif代码

SELECT 
       CreateTime, 
       
ISNULL(SUM([支付宝]), 0AS [支付宝]
       
ISNULL(SUM([手机短信]), 0AS [手机短信],
       
ISNULL(SUM([工商银行卡]), 0AS [工商银行卡]
       
ISNULL(SUM([建设银行卡]), 0AS [建设银行卡]
FROM
(
    
SELECT CONVERT(VARCHAR(10), CreateTime, 120AS CreateTime,
           
CASE PayType WHEN '支付宝'     THEN SUM(MoneyELSE 0 END AS '支付宝',
           
CASE PayType WHEN '手机短信'   THEN SUM(MoneyELSE 0 END AS '手机短信',
           
CASE PayType WHEN '工商银行卡' THEN SUM(MoneyELSE 0 END AS '工商银行卡',
           
CASE PayType WHEN '建设银行卡' THEN SUM(MoneyELSE 0 END AS '建设银行卡'
    
FROM Inpours
    
GROUP BY CreateTime, PayType
) T
GROUP BY CreateTime

 

其实行转列,关键是要理清逻辑,而且对分组(Group by)概念比较清晰。上面两个列子基本上就是行转列的类型了。但是有个问题来了,上面是我为了说明弄的一个简单列子。实际中,可能支付方式特别多,而且逻辑也复杂很多,可能涉及汇率、手续费等等(曾经做个这样一个),如果支付方式特别多,我们的CASE WHEN 会弄出一大堆,确实比较恼火,而且新增一种支付方式,我们还得修改脚本如果把上面的脚本用动态SQL改写一下,我们就能轻松解决这个问题 

ExpandedBlockStart.gif代码
DECLARE @cmdText    VARCHAR(8000);
DECLARE @tmpSql        VARCHAR(8000);

SET @cmdText = 'SELECT CONVERT(VARCHAR(10), CreateTime, 120) AS CreateTime,' + CHAR(10);
SELECT @cmdText = @cmdText + ' CASE PayType WHEN ''' + PayType + ''' THEN SUM(Money) ELSE 0 END AS ''' + PayType 
                
+ ''',' + CHAR(10)  FROM (SELECT DISTINCT PayType FROM Inpours ) T

SET @cmdText = LEFT(@cmdTextLEN(@cmdText-2--注意这里,如果没有加CHAR(10) 则用LEFT(@cmdText, LEN(@cmdText) -1)

SET @cmdText = @cmdText + ' FROM Inpours     GROUP BY CreateTime, PayType ';

SET @tmpSql ='SELECT CreateTime,' + CHAR(10);
SELECT @tmpSql = @tmpSql + ' ISNULL(SUM(' + PayType  + '), 0) AS ''' + PayType  + ''','  + CHAR(10)
                    
FROM  (SELECT DISTINCT PayType FROM Inpours ) T

SET @tmpSql = LEFT(@tmpSqlLEN(@tmpSql-2+ ' FROM (' + CHAR(10);

SET @cmdText = @tmpSql + @cmdText + ') T GROUP BY CreateTime ';
PRINT @cmdText
EXECUTE (@cmdText);

 

下面是通过PIVOT来进行行转列的用法,大家可以对比一下,确实要简单、更具可读性(呵呵,习惯的前提下)

ExpandedBlockStart.gif代码
SELECT 
        CreateTime, 
[支付宝] , [手机短信],
        
[工商银行卡] , [建设银行卡]
FROM
(
    
SELECT CONVERT(VARCHAR(10), CreateTime, 120AS CreateTime,PayType, Money
    
FROM Inpours
) P
PIVOT (
            
SUM(Money)
            
FOR PayType IN
            (
[支付宝][手机短信][工商银行卡][建设银行卡])
      ) 
AS T
ORDER BY CreateTime

 

有时可能会出现这样的错误:

消息 325,级别 15,状态 1,第 9 行

'PIVOT' 附近有语法错误。您可能需要将当前数据库的兼容级别设置为更高的值,以启用此功能。有关存储过程 sp_dbcmptlevel 的信息,请参见帮助。

这个是因为:对升级到 SQL Server 2005 或更高版本的数据库使用 PIVOT 和 UNPIVOT 时,必须将数据库的兼容级别设置为 90 或更高。有关如何设置数据库兼容级别的信息,请参阅 。 例如,只需在执行上面脚本前加上 EXEC sp_dbcmptlevel Test, 90; 就OK了, Test 是所在数据库的名称。

 

下面我们来看看列转行,主要是通过UNION ALL ,MAX来实现。假如有下面这么一个表

ExpandedBlockStart.gif代码
CREATE TABLE ProgrectDetail
(
    ProgrectName         
NVARCHAR(20), --工程名称
    OverseaSupply        INT,          --海外供应商供给数量
    NativeSupply         INT,          --国内供应商供给数量
    SouthSupply          INT,          --南方供应商供给数量
    NorthSupply          INT           --北方供应商供给数量
)

INSERT INTO ProgrectDetail
SELECT 'A'1002005050
UNION ALL
SELECT 'B'200300150150
UNION ALL
SELECT 'C'15940020320
UNION ALL
SELECT 'D'250301515

 

 我们可以通过下面的脚本来实现,查询结果如下图所示

ExpandedBlockStart.gif代码
SELECT ProgrectName, 'OverseaSupply' AS Supplier,
        
MAX(OverseaSupply) AS 'SupplyNum'
FROM ProgrectDetail
GROUP BY ProgrectName
UNION ALL
SELECT ProgrectName, 'NativeSupply' AS Supplier,
        
MAX(NativeSupply) AS 'SupplyNum'
FROM ProgrectDetail
GROUP BY ProgrectName
UNION ALL
SELECT ProgrectName, 'SouthSupply' AS Supplier,
        
MAX(SouthSupply) AS 'SupplyNum'
FROM ProgrectDetail
GROUP BY ProgrectName
UNION ALL
SELECT ProgrectName, 'NorthSupply' AS Supplier,
        
MAX(NorthSupply) AS 'SupplyNum'
FROM ProgrectDetail
GROUP BY ProgrectName

 

 

UNPIVOT 实现如下:

ExpandedBlockStart.gif代码
SELECT ProgrectName,Supplier,SupplyNum
FROM 
(
    
SELECT ProgrectName, OverseaSupply, NativeSupply,
           SouthSupply, NorthSupply
     
FROM ProgrectDetail
)T
UNPIVOT 
(
    SupplyNum 
FOR Supplier IN
    (OverseaSupply, NativeSupply, SouthSupply, NorthSupply )
) P

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/298069.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

要男女朋友有什么用?

1 题:我不要面子的嘛!2 狗都有人给撑伞了。。3 这大概就是传说中的一见钟情吧4 5 南方人说话有多软糯6 男女朋友有什么用你点的每个赞,我都认真当成了喜欢

低代码应用创新成果——轴承行业数字化智造系统(含MES/ERP/WMS)

轴承是当代机械设备中一种不可或缺的零部件,广泛应用于汽车、铁路车辆及各类工业机械和家用电器等国民经济的重要领域,是一种节约能源、提高效率的伟大发明。轴承行业作为装备制造业的先锋,一直以来都走在数字化转型的前列,引领行…

HelloSilverlight

一&#xff1a;输入姓名并选中一个日期&#xff0c;将在下面显示 二:XAML代码 <UserControl x:Class"HelloSilverlight.MainPage"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2…

21世纪7大数学难题,解决其中一个你就成为了百万富翁!

全世界只有3.14 % 的人关注了爆炸吧知识百万富翁你也可以昨天一大早&#xff0c;知识君就收到模友送的3枝红玫瑰。仔细一看&#xff0c;原来又是来跟知识君约稿的。。。知识君只能说&#xff1a;1900年&#xff0c;希尔伯特&#xff08;传送门&#xff09;在巴黎国际数学家代表…

在 Azure VM 上使用 Jitsi 搭建私人视频会议

点击上方蓝字 / 关注“汪宇杰博客”原文&#xff1a;Azure Tips And Tricks翻译&#xff1a;汪宇杰私人视频会议市面上有许多视频会议应用程序&#xff0c;例如 Zoom、Microsoft Teams 和 Skype。有时&#xff0c;您需要自己的服务&#xff0c;以让自己更安全并在自己的公司内部…

[LeetCode]119.Pascal#39;s Triangle II

题目 Given an index k, return the kth row of the Pascal’s triangle. For example, given k 3, Return [1,3,3,1]. Note: Could you optimize your algorithm to use only O(k) extra space? 思路 无 代码 /**------------------------------------* 日期&#xff1a…

终于有人做了我一直想做而不敢做的事。。

1 初中物理是不是学过&#xff0c;受力面积小&#xff0c;相应的压力就大&#xff5e;我觉得应该直接趴上去&#xff0c;一定行&#xff5e;反正我也是瞎说的2 不是我吹&#xff0c;换成是我&#xff0c;这包子能吃五屉3 交警蜀黍耐心的领着这位行人过马路&#xff0c;麻烦你快…

.NET 6 中的隐式命名空间引用

.NET 6 中的隐式命名空间引用Intro之前写过一篇隐式命名空间引用的大概介绍&#xff0c;在一些小的测试项目中也有在用&#xff0c;一直没作为示例给大家分享&#xff0c;主要原因在于之前看到了一个关于隐式命名空间引用的 Github issue 提到会有一些破坏性的变更&#xff0c;…

vscode函数跳转插件_人生苦短,我们为 Cocos Creator 开发的插件和工具

在使用 Cocos Creator 开发项目的过程中&#xff0c;为了提高开发效率我们开发了很多扩展插件&#xff0c;本文介绍常用的几款&#xff0c;抛砖引玉&#xff0c;希望给大家带来帮助。腾讯开心鼠英语网页扩展&#xff1a;运行时查看场景节点树Cocos Creator 本地项目通常会在 Ch…

SQLSERVER 日志收缩

SQL2008 的收缩日志 由于SQL2008对文件和日志管理进行了优化&#xff0c;所以以下语句在SQL2005中可以运行但在SQL2008中已经被取消&#xff1a;(SQL2005)BackupLog DNName with no_loggodumptransaction DNName with no_loggoUSE DNName DBCC SHRINKFILE (2)Go---------------…

解决win7“该文件没有与之关联的程序来执行该操作”

机器装好了win7系统。右击“计算机”管理的时候&#xff0c;出现“该文件没有与之关联的程序来执行该操作”能是因为删除了start menu下的某个文件,经过分析,找到了如下的解决方法:定位到注册表HKEY_CLASSES_ROOT\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\shell\Manage\c…

绝不能放进微波炉的10样东西,最后一个太意外

全世界只有3.14 % 的人关注了爆炸吧知识前一阵&#xff0c;网上有一段用微波炉加热葡萄的视频&#xff0c;成了新闻热点。研究员在实验中发现&#xff0c;两颗葡萄放进微波炉后&#xff0c;竟然会产生电弧。图片来源网络之前小编加热汉堡的时候&#xff0c;本来想大快朵颐一顿&…

在 .NET 6 中使用 DATEONLY 和 TIMEONLY

在 .NET 6 中使用 DATEONLY 和 TIMEONLY在 即将发布的.NET 6中&#xff0c;引入了两种期待已久的类型作为核心库的一部分。DateOnly和TimeOnly允许开发人员表示 DateTime 的日期或时间部分。这两种新类型是结构体&#xff08;值类型&#xff09;&#xff0c;可以在您的代码独立…

vue 3.0 正式版_Vuejs 3 Release:One Piece. Vuejs 3.0 正式版发布!代号:海贼王

Vuejs 3.0 在北京时间2020年9月19日凌晨&#xff0c;终于发布了 3.0 版本&#xff0c;代号&#xff1a;One Piece。此次vue3.0 为用户提供了全新的 composition-api 以及更小的包大小&#xff0c;和更好的 TypeScript 支持。Vue3.0发布链接​github.comVue 是当前非常流行的框架…

Linux IPC实践(6) --System V消息队列(3)

消息队列综合案例 消息队列实现回射客户/服务器 server进程接收时, 指定msgtyp为0, 从队首不断接收消息 server进程发送时, 将mtype指定为接收到的client进程的pid client进程发送的时候, mtype指定为自己进程的pid client进程接收时, 需要将msgtyp指定为自己进程的pid, 只接收…

100斤的铁和100斤女生哪个重?

1 你是不是有别的猫了&#xff1f;-2 兔兔这么可爱我们沾点孜然再吃会更香3 解压的最好方式4 人不如猫系列5 这演技没sei了&#xff01;&#xff01;&#xff01;6 100斤的铁和100斤女生哪个重&#xff1f;7 如果只能选一个&#xff0c;你会选什么你点的每个赞&#xff…

JailbreakMe.com-最新浏览器模式破解iPhones,iPads和iPod Touches方法

一位***建立了该网站(JailbreakMe.com)&#xff0c;可以通过浏览器登录的形式破解几乎所有的iOS&#xff0c;这包括了iPhone,iPad,和iPod Touch&#xff0c;将解除Apple对这些设备的软件限制。 用户如果想尝试未经授权的app或者想在多个不同国家使用这些设备&#xff0c;都可以…

谷歌开源3D舞蹈生成模型FACT,舞姿清奇!

文 | 御坂弟弟出品 | OSC开源社区&#xff08;ID&#xff1a;oschina2013&#xff09;谷歌开源了其基于 AIST 的 3D 舞蹈生成模型 FACT。该模型不仅可以学习音乐-运动对应关系&#xff0c;还可以生成以音乐为基础的 3D 运动序列。此前&#xff0c;谷歌层发布了大规模的多模态 3…

vue click事件_vue指令用法

vue指令指令式带有 v- 前缀的特殊特性v-text和v-html都属于指令将数据和dom做关联&#xff0c;当表达式的值改变时&#xff0c;响应式地作用在视图解决大胡子语法闪烁案例[v-cloak] {dispaly: none; }一般把v-cloak绑在Vue实例el属性绑定的节点上<!DOCTYPE html> <htm…

冒泡排序c java c,冒泡排序,c语言冒泡排序法代码

冒泡排序&#xff0c;c语言冒泡排序法代码冒泡排序冒泡排序(Bubble Sort)&#xff0c;是一种计算机科学领域的较简单的排序算法。它重复地走访过要排序的元素列&#xff0c;依次比较两个相邻的元素&#xff0c;如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元…