在线精品99_中国九九盗摄偷拍偷看_91免费版在线观看_91.app_91高清视频在线_99热最新网站

SQL如何实现行转列和列转行

149次阅读
没有评论

共计 4569 个字符,预计需要花费 12 分钟才能阅读完成。

这篇文章给大家分享的是有关 SQL 如何实现行转列和列转行的内容。丸趣 TV 小编觉得挺实用的,因此分享给大家做个参考,一起跟随丸趣 TV 小编过来看看吧。

行列互转,是一个经常遇到的需求。实现的方法,有 case when 方式和 2005 之后的内置 pivot 和 unpivot 方法来实现。
在读了技术内幕那一节后,虽说这些解决方案早就用过了,却没有系统性的认识和总结过。为了加深认识,再总结一次。
行列互转,可以分为静态互转,即事先就知道要处理多少行(列); 动态互转, 事先不知道处理多少行 (列)。

-- 创建测试环境
USE tempdb;
IF OBJECT_ID(dbo.Orders) IS NOT NULL
 DROP TABLE dbo.Orders;
CREATE TABLE dbo.Orders
 orderid int NOT NULL PRIMARY KEY NONCLUSTERED,
 orderdate datetime NOT NULL,
 empid int NOT NULL,
 custid varchar(5) NOT NULL,
 qty int NOT NULL
CREATE UNIQUE CLUSTERED INDEX idx_orderdate_orderid
 ON dbo.Orders(orderdate, orderid);
INSERT INTO dbo.Orders(orderid, orderdate, empid, custid, qty)
 VALUES(30001,  20020802 , 3,  A , 10);
INSERT INTO dbo.Orders(orderid, orderdate, empid, custid, qty)
 VALUES(10001,  20021224 , 1,  A , 12);
INSERT INTO dbo.Orders(orderid, orderdate, empid, custid, qty)
 VALUES(10005,  20021224 , 1,  B , 20);
INSERT INTO dbo.Orders(orderid, orderdate, empid, custid, qty)
 VALUES(40001,  20030109 , 4,  A , 40);
INSERT INTO dbo.Orders(orderid, orderdate, empid, custid, qty)
 VALUES(10006,  20030118 , 1,  C , 14);
INSERT INTO dbo.Orders(orderid, orderdate, empid, custid, qty)
 VALUES(20001,  20030212 , 2,  B , 12);
INSERT INTO dbo.Orders(orderid, orderdate, empid, custid, qty)
 VALUES(40005,  20040212 , 4,  A , 10);
INSERT INTO dbo.Orders(orderid, orderdate, empid, custid, qty)
 VALUES(20002,  20040216 , 2,  C , 20);
INSERT INTO dbo.Orders(orderid, orderdate, empid, custid, qty)
 VALUES(30003,  20040418 , 3,  B , 15);
INSERT INTO dbo.Orders(orderid, orderdate, empid, custid, qty)
 VALUES(30004,  20020418 , 3,  C , 22);
INSERT INTO dbo.Orders(orderid, orderdate, empid, custid, qty)
 VALUES(30007,  20020907 , 3,  D , 30);
GO

行转列 - 静态方案:

-- 行转列的静态方案一:CASE WHEN, 兼容 sql2000
select custid,
sum(case when YEAR(orderdate)=2002 then qty end) as [2002],
sum(case when YEAR(orderdate)=2003 then qty end) as [2003],
sum(case when YEAR(orderdate)=2004 then qty end) as [2004]
from orders
group by custid;
-- 行转列的静态方案二:PIVOT,sql2005 及以后版本
select *
from (select custid,YEAR(orderdate) as years,qty from orders) as ord
pivot(sum(qty) for years in([2002],[2003],[2004]))as p
GO

行转列 - 动态方案:加入了 xml 处理和 SQL 注入预防判断

-- 既然是用到了动态 SQL, 就有一个老话题:SQL 注入。建一个注入性字符的判断函数。CREATE FUNCTION [dbo].[fn_CheckSQLInjection]
 @Col nvarchar(4000)
RETURNS BIT -- 如果存在可能的注入字符返回 true, 反之返回 false
BEGIN
DECLARE @result bit;
 IF 
 UPPER(@Col) LIKE UPPER(N %0x%)
 OR UPPER(@Col) LIKE UPPER(N %)
 OR UPPER(@Col) LIKE UPPER(N % %)
 OR UPPER(@Col) LIKE UPPER(N %--%)
 OR UPPER(@Col) LIKE UPPER(N %/*%*/%)
 OR UPPER(@Col) LIKE UPPER(N %EXEC%)
 OR UPPER(@Col) LIKE UPPER(N %xp_%)
 OR UPPER(@Col) LIKE UPPER(N %sp_%)
 OR UPPER(@Col) LIKE UPPER(N %SELECT%)
 OR UPPER(@Col) LIKE UPPER(N %INSERT%)
 OR UPPER(@Col) LIKE UPPER(N %UPDATE%)
 OR UPPER(@Col) LIKE UPPER(N %DELETE%)
 OR UPPER(@Col) LIKE UPPER(N %TRUNCATE%)
 OR UPPER(@Col) LIKE UPPER(N %CREATE%)
 OR UPPER(@Col) LIKE UPPER(N %ALTER%)
 OR UPPER(@Col) LIKE UPPER(N %DROP%)
 SET @result=1
 ELSE
 SET @result=0
 return @result
-- 行转列的动态方案一:CASE WHEN, 兼容 sql2000
DECLARE @T TABLE (years INT NOT NULL PRIMARY KEY);
INSERT INTO @T 
SELECT DISTINCT YEAR(orderdate) from orders;
DECLARE @Y INT;
SET @Y=(SELECT MIN(years) from @T);
DECLARE @SQL NVARCHAR(4000)=N 
WHILE @Y IS NOT NULL
BEGIN
 SET @SQL=@SQL+N ,sum(case when YEAR(orderdate)= +CAST(@Y AS NVARCHAR(4)) +N  then qty end) as  +QUOTENAME(@Y);
 SET @Y=(SELECT MIN(years) from @T where years 
IF dbo.fn_CheckSQLInjection(@SQL)=0
SET @SQL=N SELECT custid +@SQL+N  FROM orders group by custid 
PRINT @SQL
EXEC sp_executesql @SQL
-- 行转列的动态方案二:PIVOT,sql2005 及以后版本
DECLARE @T TABLE (years INT NOT NULL PRIMARY KEY);
INSERT INTO @T 
SELECT DISTINCT YEAR(orderdate) from orders;
DECLARE @Y INT;
SET @Y=(SELECT MIN(years) from @T);
DECLARE @SQL NVARCHAR(4000)=N 
 -- 这里使用了 xml 处理来处理类组字符串
SET @SQL=STUFF((SELECT N , +QUOTENAME(years) FROM @T
 FOR XML PATH()),1,1,N 
IF dbo.fn_CheckSQLInjection(@SQL)=0
SET @SQL=N select * from (select DISTINCT custid,YEAR(orderdate) as years,qty from orders) as ord
pivot(sum(qty) for years in(+@SQL+N))as p 
PRINT @SQL;
EXEC SP_EXECUTESQL @SQL;
GO

列转行:

-- 列转行的静态方案:UNPIVOT,sql2005 及以后版本
SELECT * FROM dbo.pvtCustOrders
SELECT custid,years,qty
from dbo.pvtCustOrders
unpivot(qty for years in([2002],[2003],[2004]))as up
-- 列转行的动态方案:UNPIVOT,sql2005 及以后版本
-- 因为行是动态所以这里就从 INFORMATION_SCHEMA.COLUMNS 视图中获取列来构造行,同样也使用了 XML 处理。DECLARE @SQL NVARCHAR(4000)=N 
SET @SQL=STUFF((SELECT N , +QUOTENAME(COLUMN_NAME ) FROM INFORMATION_SCHEMA.COLUMNS
WHERE ORDINAL_POSITION 1 AND TABLE_NAME= PvtCustOrders 
FOR XML PATH()),1,1,N )
SET @SQL=N SELECT custid,years,qty
 from dbo.pvtCustOrders
 unpivot(qty for years in( +@SQL+))as up 
PRINT @SQL;
EXEC SP_EXECUTESQL @SQL;

感谢各位的阅读!关于“SQL 如何实现行转列和列转行”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-04发表,共计4569字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)
主站蜘蛛池模板: 国产 麻豆 日韩 欧美 久久 | 99久久精品国产交换 | 内射中出无码护士在线 | 精品小视频在线 | 欧美日韩一区二区综合在线视频 | 欧美日韩国产另类一区二区三区 | 精品一区二区三区三区 | 中文欧美日韩 | 欧美性a欧美在线 | 亚洲日韩av一区二区三区中文 | 亚洲天堂精品在线观看 | 亚洲日本综合 | 久久久久亚洲波多野结衣 | 国产亚洲精品久久久极品美女 | 亚洲精品456 | 最新国产成人综合在线观看 | 日本久久久久久久做爰片日本 | 国产免费一区二区视频 | 亚洲国产欧美在线人成大黄瓜 | 午夜免费福利小电影 | 亚洲欧美成人在线 | 国产精品久久久久影视青草 | 亚 洲 成 人 动 漫在线 | 国产精品嫩草视频永久网址 | 亚洲av无码欧洲av无码网站 | 欧美亚洲在线观看 | 日本黄大片视频在线播放 | 在线精品视频成人网 | 男女啪啪激烈高潮喷出gif免费 | 成人a毛片免费全部播放 | 99久久影视| 丰满人妻被黑人猛烈进入 | 亚洲国产一区二区三区a毛片 | 欧美日韩一区二区高清视 | 精品国产精品久久一区免费式 | 欧美一级大黄特黄毛片视频 | 天仙tv国产福利视频 | 日本丰满护士爆乳xxxx | 亚洲日韩欧美一区久久久久我 | 久久99热久久精品99 | 日本黄色大片网站 |