T-SQL 经典行专列、列转行,分页及存储过程

合集下载

Sql的行列(纵横表)转换

Sql的行列(纵横表)转换

Sql的⾏列(纵横表)转换创建表scores⼀、传统的⾏列转换纵表转横表我们要转成的横表是这样⼦的:既然这个表只有两列,那么可以根据姓名进⾏分组。

先把姓名拼凑出来,后⾯的分数我们再想办法。

select姓名from scores group by 姓名结果:分析:1. 我们先拿到语⽂这个科⽬的分数。

既然我们⽤到了group by 语句,这⾥肯定要⽤聚合函数来求分数。

2. ⽽且我们只需要语⽂这⼀科的成绩,分组出来的⼀共有 3列,分别是语⽂、数学、物理。

那么就需要判断科⽬来取分数。

这⾥符合我们需求的 case 语句就登场了。

它和c#中switch-case 作⽤⼀样。

sql case 语句语法:case字段when 值1 then 结果when 值2 then 结果2...else默认结果endselect姓名,SUM(case课程 when '语⽂' then 分数else0 end) as语⽂from scores group by 姓名结果:既然语⽂的分数取到了,其他科⽬改变下条件就可以了。

完整的sql:select姓名,SUM(case课程 when '语⽂' then 分数else0 end) as语⽂,SUM(case课程 when '数学' then 分数else0 end) as数学,SUM(case课程 when '物理' then 分数else0 end) as物理from scores group by 姓名横表转纵表我们先把刚刚转好的表,插⼊⼀个新表Scores2中。

select姓名,SUM(case课程 when '语⽂' then 分数else0 end) as语⽂,SUM(case课程 when '数学' then 分数else0 end) as数学,SUM(case课程 when '物理' then 分数else0 end) as物理into scores2from scores group by 姓名我们也先把张三和李四的语⽂成绩查出来。

sqlserver行转列及列转行的使用

sqlserver行转列及列转行的使用

sqlserver⾏转列及列转⾏的使⽤在我们使⽤的数据库表中经常需要⽤到⾏列互相转换的情况,使⽤sql 的关键词 UNPIVOT(列转⾏)和PIVOT(⾏转列)可轻松实现⾏列转换。

⼀、列转⾏:员⼯⽉份排班表存储是采⽤1号~31号作为列的⽅式进⾏存储的现通过 UNPIVOT 将每天的班次⽤⾏进⾏展⽰,sql 如下:SELECT distinct t.Pb_Job_No,t.Year_Month ,convert(int, REPLACE( t.day,'day','')) as day,classno FROM Scheduling_InfoUNPIVOT(classno FOR day IN(Day1,Day2,Day3,Day4,Day5,Day6,Day7 ,Day8 ,Day9,Day10,Day11,Day12,Day13,Day14,Day15,Day16,Day17,Day18,Day19,Day20,Day21,Day22,Day23,Day24,Day25,Day26,Day27,Day28,Day29,Day30,Day31)) Twhere Year_Month='2020-05'and Pb_Job_No='0997'order by Pb_Job_No,day这⾥的关键词是UNPIVOT(classno FOR day IN('⽇期列名') ,其中 ‘day’是存储⽇期的列,classno 是存储原有班次的列查询结果如下:⼆、⾏转列:如果将上述列转⾏查询的结果表定义为 Scheduling_DayInfo,进⾏逆转为原始表,那么sql 语句为:SELECT Pb_Job_No,[1],[2] ,[3] ,[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[20],[21],[22],[23],[24],[25],[26],[27],[28],[29],[30],[31]fromScheduling_DayInfo PIVOT ( max(classno) FOR[day]IN([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[20],[21],[22],[23],[24],[25],[26],[27],[28],[29],[30],[31]) )t结果为:此处的 in 必须是列 day 中的值,使⽤pivot 需要⽤到聚合函数(sum,count,avg,max,min 等),使⽤的场景如考试成绩 sum(score) ,年度销售业绩等,由于此处不需要统计但是⼜必须⽤聚合函数,所以使⽤max 凑合,因为这些函数可以接受字符类型的参数。

sql语句中行转列,以及列转行

sql语句中行转列,以及列转行

sql语句中⾏转列,以及列转⾏⾏转列:图1: --------------------------------------------》》》》 图2:sql执⾏原理:根据id分组,然后select后⾯创建多次查询,⽣成列信息(利⽤case语句给分group by后的语句分类)-- ⾏转列select t.id,sum(case name when'仓库1'then t.num else NULL end) 仓库1,sum(case name when'仓库2'then t.num else NULL end) 仓库2,sum(case name when'仓库3'then t.num else NULL end) 仓库3from tGROUP BY t.id;列转⾏:图1: --------------------------------------------》》》》 图2:第⼀步:sql执⾏原理:每个select语句只查某⼀个字段的值,创建多个查询,然后将多个select语句通过union链接,实现⼀条多列数据变成多⾏⼀列;⽐如⼀⾏仓库1,仓库2,仓库3 最后变成多⾏select p.id, '仓库1' name, p.`仓库1` numfrom pr punionselect p.id, '仓库2' name, p.`仓库2` numfrom pr punionselect p.id, '仓库3' name, p.`仓库3` numfrom pr p执⾏结果:第⼆步:去掉为null的,即不存在⾏select*from (select p.id, '仓库1' name, p.`仓库1` num from pr punionselect p.id, '仓库2' name, p.`仓库2` num from pr punionselect p.id, '仓库3' name, p.`仓库3` num from pr p ) T where T.num is not null order by id, name。

mssql数据库表行转列,列转行终极方案

mssql数据库表行转列,列转行终极方案

mssql数据库表⾏转列,列转⾏终极⽅案复制代码代码如下:--⾏转列问题--建⽴測試環境Create Table TEST(DATES Varchar(6),EMPNO Varchar(5),STYPE Varchar(1),AMOUNT Int)--插⼊數據Insert TEST Select '200605', '02436', 'A', 5Union All Select '200605', '02436', 'B', 3Union All Select '200605', '02436', 'C', 3Union All Select '200605', '02436', 'D', 2Union All Select '200605', '02436', 'E', 9Union All Select '200605', '02436', 'F', 7Union All Select '200605', '02436', 'G', 6Union All Select '200605', '02438', 'A', 7Union All Select '200605', '02438', 'B', 8Union All Select '200605', '02438', 'C', 0Union All Select '200605', '02438', 'D', 3Union All Select '200605', '02438', 'E', 4Union All Select '200605', '02438', 'F', 5Union All Select '200605', '02438', 'G', 1GO--測試--如果STYPE固定,可以這麼寫SelectDATES,EMPNO,SUM(Case STYPE When 'A' Then AMOUNT Else 0 End) As A,SUM(Case STYPE When 'B' Then AMOUNT Else 0 End) As B,SUM(Case STYPE When 'C' Then AMOUNT Else 0 End) As C,SUM(Case STYPE When 'D' Then AMOUNT Else 0 End) As D,SUM(Case STYPE When 'E' Then AMOUNT Else 0 End) As E,SUM(Case STYPE When 'F' Then AMOUNT Else 0 End) As F,SUM(Case STYPE When 'G' Then AMOUNT Else 0 End) As GFrom TESTGroup By DATES,EMPNOOrder By DATES,EMPNO--如果STYPE不固定,⽤動態語句Declare @S Varchar(1000)Set @S=''Select @S=@S+',SUM(Case STYPE When '''+STYPE+''' Then AMOUNT Else 0 End) As '+STYPE From (Select Distinct STYPE From TEST) A Order By STYPESet @S='Select DATES,EMPNO'+@S+' From TEST Group By DATES,EMPNO Order By DATES,EMPNO'EXEC(@S)GO--如果被转置的是数字类型的话,应⽤下列语句DECLARE @S VARCHAR(1000)SET @S='SELECT DATES,EMPNO 'SELECT @S=@S+',['+STYPE+']=SUM(CASE WHEN STYPE='''+STYPE+''' THEN AMOUNT ELSE 0 END)'FROM (Select Distinct STYPE From TEST) A Order By STYPESET @S=@S+' FROM TEST GROUP BY DATES,EMPNO'EXEC(@S)如果是列转⾏的话直接Union All就可以了例如:city style color 46 48 50 52长沙 S6MF01002 152 1 2 2 1长沙 S6MF01002 201 1 2 2 1上⾯到下⾯的样⼦city style color size qty长沙 S6MF01002 152 46 1长沙 S6MF01002 152 48 2长沙 S6MF01002 152 50 2长沙 S6MF01002 152 52 1长沙 S6MF01002 201 46 1长沙 S6MF01002 201 48 2长沙 S6MF01002 201 50 2长沙 S6MF01002 201 52 1Select City,Style,Color,[46] From Test Union allSelect City,Style,Color,[48] From Test Union allSelect City,Style,Color,[50] From Test Union allSelect City,Style,Color,[52] From Test 就可以了。

SQLSERVER行转列和列转行

SQLSERVER行转列和列转行

1:行转列子查询,获取一定数据集结果SELECT objid,action,count(1) AS [count] FROM T_MyAttention WHERE objid IN (SELECT TOP 10 objid FROM T_MyAttentiontma GROUP BY objid ORDER BY count(1) DESC)GROUP BY objid,action下面用行转列语法获取最终结果select *from(SELECT objid,action,count(1) AS [count] FROM T_MyAttention WHERE objid IN (SELECT TOP 10 objid FROM T_MyAttentiontma GROUP BY objid ORDER BY count(1) DESC)GROUP BY objid,action) tpivot ( sum(count) for t.action in ([1],[2],[3],[4])) as ourpivot微软官方的图:2:列转行怎么把一条记录拆分成几条记录?User No. A B C1 1 21 34 241 2 42 25 16 RESULT:User No. Type Num1 1 A 211 1 B 341 1 C 241 2 A 421 2 B 251 2 C 16declare @t table(usserint ,no int ,a int,bint, c int) insert into @t select 1,1,21,34,24union all select 1,2,42,25,16SELECT usser,no,Type=attribute, Num=valueFROM @tUNPIVOT(value FOR attribute IN([a], [b], [c])) AS UPV列转行备注value FOR attribute IN([a], [b], [c])这句话中,a,b,c是列的名字,但是列名不能出现在上句的select语句中。

sql行列转换方法整理

sql行列转换方法整理

1.--行‎列转换原‎表: ‎姓名‎科目‎成绩‎‎‎张三‎语文‎ 8‎0‎‎张三‎‎数学‎90‎‎‎张三‎物理‎ 85‎‎‎李四‎语‎文‎85‎‎李‎四‎物理‎ 82‎‎‎李四‎英语‎ 9‎0‎‎李四‎‎政治‎70‎‎‎王五‎英语‎ 90‎转换后‎的表:‎姓名‎数‎学‎物理‎英语‎语文‎政‎治‎‎‎‎‎李四‎‎ 0 ‎‎ 82 ‎‎ 90 ‎‎85 ‎ 7‎0‎‎‎‎‎王五‎‎0 ‎‎ 0 ‎‎ 90 ‎‎0 ‎‎0‎‎‎‎‎张三‎‎90 ‎‎85 ‎‎ 0 ‎‎80 ‎‎0实例‎:cre‎a te t‎a ble ‎c j -‎-创建表c‎j(‎ ID‎‎ Int‎IDEN‎T ITY ‎(1,1)‎‎n ot n‎u ll, ‎--创建列‎I D,并且‎每次新增一‎条记录就会‎加1 ‎ Nam‎e‎Varc‎h ar(5‎0), ‎‎Subj‎e ct ‎V arch‎a r(50‎),‎ Res‎u lt ‎Int,‎‎ pri‎m ary ‎k ey (‎I D) ‎ -‎-定义ID‎为表cj的‎主键‎)‎;--T‎r unca‎t e ta‎b le c‎j--S‎e lect‎* fr‎o m cj‎Inse‎r t in‎t o cj‎Sele‎c t '张‎三','语‎文',80‎unio‎n all‎Sel‎e ct '‎张三','‎数学',9‎0 uni‎o n al‎lSel‎e ct '‎张三','‎物理',8‎5 uni‎o n al‎lSel‎e ct '‎李四','‎语文',8‎5 uni‎o n al‎lSel‎e ct '‎李四','‎物理',8‎2 uni‎o n al‎lSel‎e ct '‎李四','‎英语',9‎0 uni‎o n al‎lSel‎e ct '‎李四','‎政治',7‎0 uni‎o n al‎lSel‎e ct '‎王五','‎英语',9‎0--行‎列转换D‎e clar‎e @sq‎l var‎c har(‎8000)‎Set ‎@sql ‎= 'Se‎l ect ‎N ame ‎a s 姓名‎'Sel‎e ct @‎s ql =‎@sql‎+ ',‎s um(c‎a se S‎u bjec‎t whe‎n '''‎+Subj‎e ct+'‎'' th‎e n Re‎s ult ‎e lse ‎0 end‎) ['+‎S ubje‎c t+']‎'fro‎m (se‎l ect ‎d isti‎n ct S‎u bjec‎t fro‎m cj)‎as c‎j --‎把所有唯一‎的科目的名‎称都列举出‎来Sel‎e ct @‎s ql =‎@sql‎+' fr‎o m cj‎grou‎p by ‎n ame'‎‎2. 行列‎转换--合‎并原表:‎班级‎学‎号‎‎‎ 1‎‎‎1‎‎‎1 ‎‎ 2‎‎‎1 ‎‎ 3‎‎‎2 ‎‎ 1‎‎‎2 ‎‎ 2‎‎‎3 ‎‎ 1转‎换后的表:‎班级‎学号‎‎‎‎‎‎‎ 1‎ 1,‎2,3‎‎‎‎‎ 2 ‎1,2‎‎‎‎‎ 3 ‎ 1 ‎实例‎:Cre‎a te t‎a ble ‎C lass‎N o -‎-创建表C‎l assN‎o(‎ ID‎Int ‎I DENT‎I TY(1‎,1) ‎n ot n‎u ll, ‎--创建‎列ID,并‎且每次新增‎一条记录就‎会加1 ‎ Cl‎a ss ‎V arch‎a r(50‎), ‎--班级‎列‎Numb‎e r Va‎r char‎(50),‎ -‎-学号列‎ P‎r imar‎y Key‎(ID) ‎‎ --定‎义ID为表‎C lass‎N o的主键‎);-‎-Trun‎c ate ‎T able‎Clas‎s No-‎-Sele‎c t * ‎f rom ‎C lass‎N oIn‎s ert ‎I nto ‎C lass‎N oSe‎l ect ‎1,1 U‎n ion ‎a llS‎e lect‎1,2 ‎U nion‎all‎S elec‎t 1,3‎Unio‎n all‎Sele‎c t 2,‎1 Uni‎o n al‎lSel‎e ct 2‎,2 Un‎i on a‎l lSe‎l ect ‎3,1‎创建一个合‎并的函数‎--Dro‎p Fun‎c tion‎KFRe‎t urn‎C reat‎e Fun‎c tion‎KFRe‎t urn(‎@Clas‎s Var‎c har(‎50))‎R etur‎n s Va‎r char‎(8000‎)as ‎Begi‎nDec‎l are ‎@str ‎V arch‎a r(80‎00)S‎e t @s‎t r = ‎''Se‎l ect ‎@str ‎= @st‎r + c‎a st(N‎u mber‎as V‎a rcha‎r(50)‎) + ‎',' f‎r om C‎l assN‎o Whe‎r e Cl‎a ss =‎@Cla‎s sS‎e t @s‎t r = ‎S ubSt‎r ing(‎@str,‎1,len‎(@str‎)-1)En‎d--‎调用自定义‎函数得到结‎果Sel‎e ct D‎i stin‎c t Cl‎a ss,d‎b o.KF‎R etur‎n(Cla‎s s) F‎r om C‎l assN‎o3‎:列转行‎--Dro‎p Tab‎l e Co‎l umnT‎o Row‎C reat‎e tab‎l e Co‎l umnT‎o Row‎(‎I D In‎t IDE‎N TITY‎(1,1)‎ not‎null‎, --‎创建列ID‎,并且每次‎新增一条记‎录就会加1‎a‎ int‎,‎b in‎t,‎c i‎n t,‎ d ‎i nt,‎ e ‎int,‎f‎ int‎,‎g in‎t,‎h i‎n t,‎ Pri‎m ary ‎K ey(I‎D) ‎‎--定义I‎D为表Co‎l umnT‎o Row的‎主键‎)‎;--T‎r unca‎t e Ta‎b le C‎o lumn‎T oRow‎--S‎e lect‎* fr‎o m Co‎l umnT‎o Row‎I nser‎t Int‎o Col‎u mnTo‎R ow‎S elec‎t 15,‎9,1,0‎,1,2,‎4,2 U‎n ion ‎a llS‎e lect‎22,3‎4,44,‎5,6,7‎,8,7 ‎U nion‎all‎S elec‎t 33,‎44,55‎,66,7‎7,88,‎99,12‎Dec‎l are ‎@sql ‎V arch‎a r(80‎00)S‎e t @s‎q l = ‎''Se‎l ect ‎@sql ‎= @sq‎l + r‎t rim(‎n ame)‎+ ' ‎f rom ‎C olum‎n ToRo‎w uni‎o n al‎l Sel‎e ct '‎from‎SysC‎o lumn‎s Whe‎r e id‎= ob‎j ect_‎i d('C‎o lumn‎T oRow‎')Se‎t @sq‎l = S‎u bStr‎i ng(@‎s ql,1‎,len(‎@sql)‎-70)‎--70的‎长度就是这‎个字符串'‎f rom ‎C olum‎n ToRo‎w uni‎o n al‎l Sel‎e ct I‎D fro‎mCol‎u mnTo‎R ow u‎n ion ‎a ll S‎e lect‎',因为‎它会把ID‎这一列的值‎也算进去,‎所以要把它‎截掉Ex‎e c ('‎S elec‎t ' +‎@sql‎+ ' ‎f rom ‎C olum‎n ToRo‎w')‎4. 如‎何取得一个‎数据表的所‎有列名方‎法如下:先‎从syso‎b ject‎s系统表中‎取得数据表‎的syst‎e mid,‎然后再sy‎s colu‎m ns表中‎取得该数据‎表的所有列‎名。

Sql2008的行列转换之行转列

Sql2008的行列转换之行转列

Sql2008的⾏列转换之⾏转列今天在⼯作的时候遇到了⾏列转换的问题,记得去年有⼀段时间经常写,但是许久不⽤已经记不太得了。

好记性不如烂笔头,忙完之后赶紧记录⼀下。

关键字:PIVOT(⾏转列),UNPIVOT(列转⾏)先说说 PIVOT(⾏转列)这是我今天遇到的问题PIVOT(⾏专列)主要语法:PIVOT(聚合函数(列) FOR 列 in (…) )AS P完整语法:table_sourcePIVOT(聚合函数(value_column)FOR pivot_columnIN(<column_list>))举例(这个最重要,没有例⼦只有概念的⽂章,不是好⽂章)我这⾥有⼀张表其中OperationDate这⾥⼀列是⽇期,要求是:对⽇期进⾏分组,统计Testuser每天的操作。

最重要的是⽇期要做为列名显⽰,如下图直接贴sql语句DECLARE @columnNme NVARCHAR(4000)SELECT @columnNme = ISNULL(@columnNme + ',', '') + QUOTENAME(CONVERT(varchar(100), [OperationDate], 23))FROM [Test].[dbo].[OperationData]group by CONVERT(varchar(100), [OperationDate], 23)order by CONVERT(varchar(100), [OperationDate], 23)--select(@columnNme )---上⾯⼀部分,是取出不重复的⽇期,⼀会⼉要做为列名, QUOTENAME是在“xxxx-xx-xx”这种不规则的列名合法化,它会变成[xxxx-xx-xx] , 加了两个[ ]Declare @sql NVARCHAR(4000)set @sql = 'select * from(SELECT erName,CONVERT(varchar(100), od.[OperationDate], 23) as ⽇期,COUNT(1) as 浏览数FROM [Test].[dbo].[OperationData] as odgroup by CONVERT(varchar(100), od.[OperationDate], 23),erName) as tpivot (max(浏览数) for ⽇期in ('+@columnNme +')) as result'--select(@sql)EXEC( @sql)这种写法是列名数量不固定的时候,需要动态⽣成。

Sqlserver中将数据行转列列转行(一)

Sqlserver中将数据行转列列转行(一)

Sqlserver中将数据⾏转列列转⾏(⼀)在做⼀些数据分析与数据展⽰时,经常会遇到⾏转列,列转⾏的需求,今天就来总结下:在开始之前,先来创建⼀个临时表,并且写⼊⼀些测试数据:/*第⼀步:创建临时表结构*/CREATE TABLE #Student --创建临时表(StuName nvarchar(20), --学⽣名称StuSubject nvarchar(20),--考试科⽬StuScore int--考试成绩)DROP TABLE #Student --删除临时表SELECT*FROM #Student --查询所有数据/*第⼆步:写⼊测试数据*/--张三INSERT INTO #Student(StuName,StuSubject,StuScore) values ('张三','语⽂',80);INSERT INTO #Student(StuName,StuSubject,StuScore) values ('张三','数学',75);INSERT INTO #Student(StuName,StuSubject,StuScore) values ('张三','英语',65);--李四INSERT INTO #Student(StuName,StuSubject,StuScore) values ('李四','语⽂',36);INSERT INTO #Student(StuName,StuSubject,StuScore) values ('李四','数学',56);INSERT INTO #Student(StuName,StuSubject,StuScore) values ('李四','英语',38);--王五INSERT INTO #Student(StuName,StuSubject,StuScore) values ('王五','语⽂',69);INSERT INTO #Student(StuName,StuSubject,StuScore) values ('王五','数学',80);INSERT INTO #Student(StuName,StuSubject,StuScore) values ('王五','英语',78);--赵六INSERT INTO #Student(StuName,StuSubject,StuScore) values ('赵六','语⽂',80);INSERT INTO #Student(StuName,StuSubject,StuScore) values ('赵六','数学',80);INSERT INTO #Student(StuName,StuSubject,StuScore) values ('赵六','英语',95);数据准备好了之后,开始今天的正题:⼀:⾏转列,下⾯是转换之前与之后的截图对⽐⽅法1:使⽤Case when ⽅式SELECT StuSubject,SUM(CASE WHEN StuName='张三' THEN StuScore END) as '张三',SUM(CASE WHEN StuName='王五' THEN StuScore END) as '王五',SUM(CASE WHEN StuName='赵六' THEN StuScore END) as '赵六'FROM #StudentGROUP BY StuSubject适⽤场景:要转换成多少列确定,⽐如上⾯,已经确切知道只有张三、李四、王五、赵六四个⼈;缺点:1.如果有20个⼈,要写20个CASE 判断,写起来恶⼼,代码不优雅;2.⽆法解决列是动态产⽣的问题,⽐如按⽉份⽇期转换2⽉有可能28天,其它⽉份30天;⽅法2:使⽤PIVOT 关键字SELECT *FROM #StudentPIVOT(SUM(StuScore) FOR [StuName] IN("李四","王五","张三","赵六")) AS T适⽤场景:要转换成多少列确定,⽐如上⾯,已经确切知道只有张三、李四、王五、赵六四个⼈;缺点:1.⽆法解决列是动态产⽣的问题,⽐如按⽉份⽇期转换2⽉有可能28天,其它⽉份30天;⽅法3:使⽤PIVOT、EXEC关键Declare@StuName varchar(100);Declare@sql nvarchar(4000)--步骤1.假设列不固定,是动态产⽣的,需要先将所有列组合成⼀个长字符串,⽐如A,B,C ,SELECT@StuName=STUFF((SELECT','+ DS_descriptionFROM Base_SalaColumnWHERE DS_type='3'AND DS_means!='不参与'FOR xml path('')),1,1,'')Print@StuName--步骤2.由于动态产⽣的列,脚本不能执⾏,所以⽤Exec来执⾏,把脚本写成⼀个字符串。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

T-SQL 经典编程说明:本实例是以SQL Server 2005 为运行环境的。

准备工作:创建一个名为DB 的数据库(CREATE DATABASE DB)。

一、T-SQL 行转列1、创建如下表CREATE TABLE [Scores] ([ID] INT IDENTITY(1,1),--自增标识[StuNo] INT,--学号[Subject] NVARCHAR(30),--科目[Score] FLOAT--成绩)GOINSERT INTO [Scores]SELECT 100,'语文', 80 UNIONSELECT 100,'数学', 75 UNIONSELECT 100,'英语', 70 UNIONSELECT 100,'生物', 85 UNIONSELECT 101,'语文', 80 UNIONSELECT 101,'数学', 90 UNIONSELECT 101,'英语', 70 UNIONSELECT 101,'生物', 85CREATE TABLE [Student] ([ID] INT IDENTITY(100,1),--自增标识,学号[StuName] NVARCHAR(30),--姓名[Sex] NVARCHAR(30),--性别[Age] CHAR(2)--年龄)GOINSERT INTO [Student]SELECT'张三','男', 80 UNIONSELECT'李四','女', 75两表的数据如下图:2、通过CASE…WHEN 语句和GROUP BY…聚合函数来实现行转列SELECTStuNo AS'学号',MAX(CASE Subject WHEN'语文'THEN Score ELSE 0 END)AS'语文',MAX(CASE Subject WHEN'数学'THEN Score ELSE 0 END)AS'数学',MAX(CASE Subject WHEN'英语'THEN Score ELSE 0 END)AS'英语',MAX(CASE Subject WHEN'生物'THEN Score ELSE 0 END)AS'生物',SUM(Score)AS'总分',AVG(Score)AS'平均分'FROM dbo.[Scores]GROUP BY StuNoORDER BY StuNo ASC结果如下图:3、通过JOIN…ON 实现两表联接,显示出学生姓名SELECTMAX(StuNo)AS'学号',StuName AS'姓名',MAX(CASE Subject WHEN'语文'THEN Score ELSE 0 END)AS'语文',MAX(CASE Subject WHEN'数学'THEN Score ELSE 0 END)AS'数学',MAX(CASE Subject WHEN'英语'THEN Score ELSE 0 END)AS'英语',MAX(CASE Subject WHEN'生物'THEN Score ELSE 0 END)AS'生物',SUM(Score)AS'总分',AVG(Score)AS'平均分'FROM dbo.[Scores] A join [Student] B on(A.StuNo=B.ID)GROUP BY StuNameORDER BY StuName ASC结果如下图:4、通过PIVOT 实现行转列SELECTStuNo AS'学号',StuName AS'姓名',AVG(语文)AS'语文',AVG(数学)AS'数学',AVG(英语)AS'英语',AVG(生物)AS'生物'FROM [Scores]PIVOT(AVG(Score)FOR Subject IN(语文,数学,英语,生物))AS NewScoresJOIN [Student] ON(NewScores.StuNo=Student.ID) GROUP BY NewScores.StuNo,StuNameORDER BY StuName ASC结果如下图:二、T-SQL列转行1、创建数据表并插入4 条数据CREATE TABLE [StudentScores] ([ID] INT IDENTITY(1,1),--自增标识[StuNo] INT,--学号[Chinese] NVARCHAR(30),--语文[Mathematics] NVARCHAR(30), --数学[English] NVARCHAR(30),--英语[Biology] NVARCHAR(30) --生物)GOINSERT INTO [StudentScores]SELECT 100, 80, 85, 75, 80 UNIONSELECT 101, 90, 80, 70, 75 UNIONSELECT 102, 95, 90, 80, 70 UNIONSELECT 103, 60, 70, 80, 85数据如下图:2、通过UNION ALL…MAX 实现列转行SELECT StuNo,'Chinese'AS Subject,MAX(Chinese)AS'Score'FROM [StudentScores]GROUP BY [StuNo]UNION ALLSELECT StuNo,'Mathematics'AS Subject, MAX(Mathematics)AS'Score' FROM [StudentScores]GROUP BY [StuNo]UNION ALLSELECT StuNo,'English'AS Subject,MAX(English)AS'Score'FROM [StudentScores]GROUP BY [StuNo]UNION ALLSELECT StuNo,'Biology'AS Subject,MAX(Biology)AS'Score'FROM [StudentScores]GROUP BY [StuNo]结果如下图:3、用UNPIVOT 实现列转行SELECT StuNo, Subject, ScoreFROM [StudentScores]UNPIVOT(Score FOR Subject IN([Chinese], [Mathematics], [English], [Biology]) )AS NewStudentScores三、T-SQL 分页1、创建数据库并插入40000 条数据CREATE TABLE [Pagin] ([ID] INT IDENTITY(1,1),--自增标识[Number] INT,--编号[Type] NVARCHAR(30),--类型[Count] INT--数量)GOdeclare @i intset @i = 0while(@i<10000)beginINSERT INTO [Pagin] SELECT 10000+@i,'A类', 80+@i%5INSERT INTO [Pagin] SELECT 10000+@i,'B类', 60+@i%10INSERT INTO [Pagin] SELECT 10000+@i,'C类', 70+@i%8INSERT INTO [Pagin] SELECT 10000+@i,'D类', 90+@i%3set @i = @i + 1end2、通过TOP 实现分页方案一:两次TOP 实现,原型如下SELECT*FROM(SELECT TOP 5 *FROM(SELECT TOP 25 *FROM [Pagin] WHERE ID>0 ORDER BY ID ASC )AS TEMPTABLE1 ORDER BY ID DESC)AS TEMPTABLE2 ORDER BY ID ASCSELECT TOP 5 *FROM(SELECT TOP 25 *FROM [Pagin] WHERE ID>0 ORDER BY ID ASC)AS TEMPTABLE1 ORDER BY ID DESC说明:第一个 TOP 表示页面容量,第二个 TOP 表示页面容量*当前页码数。

弊病:1、强制排序,否则不能分页,虽然目前基本上查询表都要排序。

2、排序字段不能有空值即null,否则分页结果不符实际情况。

3、多次order by 速度会快吗,有待我进一步大数据量测试。

方案二:两次TOP 基于NOT IN 实现,原型如下select top 5 *from [Pagin]where ID not in(select top 25 ID from [Pagin] order by ID)order by ID说明:第一个 TOP 表示页面容量,第二个 TOP 表示页面容量*当前页码数。

弊病:1、强制排序。

2、排序列必须是唯一列,否则分页情况不符实际。

3、使用not in,速度慢。

方案三:两次TOP 基于MAX 或MIN 实现,原型如下select top 5 *from [Pagin]where ID >(select max(p.ID)from(select top25 ID from[Pagin] order by id)as p)order by ID说明:第一个 TOP 表示页面容量,第二个 TOP 表示页面容量*当前页码数。

弊病:1、强制排序。

2、排序列必须是唯一列,否则分页情况不符实际。

最后总结:在sqlserver 分页中,第二第三种方案基本上是淘汰掉的,因为现在基本上什么表都是根据添加时间来排序,所以那两种方案没有用,真亏作者也敢发布出来,只有第一种方案还是稍微能用一下,但还是要复杂的拼sql 语句,不方便,要通用于所有表有点难度,象oracle 就很方便了,基于rownum ,传入一个sql 查询语句,这个查询语句爱怎么写就怎么写,反正保证它得到一个结果集就行,不像sqlserver又是要求唯一健又是要求必须排序,把一个结果集颠来倒去,不慢才怪呢。

相关文档
最新文档