项目经验之:SQL数据库行列转换(精华)
动态SQL的练习与总结
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1 --===============由行列转换普通==================================
2 --部门 姓名 工资
3 ------------------- -------- -----
4 --A JACK 20
5 --B Tom 30
6 --A JONE 80
7 --B peter 30
8 --
9 --结果
10 --
11 --部门 姓名 工资
12 --------- ----------- ----
13 --A JACK,JONE 100
14 --B Tom,peter 60
15 if object_id('t1') is not null
16 drop table t1
17 go
18 create table t(部门 varchar(10),姓名 varchar(10),工资 int)
19 insert t select 'A','JACK',20
20 union all select 'B','Tom',30
21 union all select 'A','Jone',80
22 union all select 'B','Peter',30
23 go
24 if object_id('fun') is not null
25 drop function fun
26 go
27 create function fun(@dp varchar(50))
28 returns varchar(8000)
29 as
30 begin
31 declare @sql varchar(5000)
32 set @sql = ''
33 select @sql = @sql + ',' + 姓名 from t1 where 部门 = @dp
34 return stuff(@sql,1,1,'') --去掉前面的,
35 end
36
37 go
38 select distinct 部门,dbo.fun(部门),sum(工资) from t1 group by 部门
39 go
40 --====================行列转换合并========================
41 --Name Subject Result
42 --张三 语文 80
43 --张三 数学 90
44 --张三 物理 85
45 --李四 语文 85
46 --李四 数学 92
47 --李四 物理 82
48 --
49 --想变成
50 --姓名 语文 数学 物理
51 --张三 80 90 85
52 --李四 85 92 82
53 if object_id('t1') is not null
54 drop table t1
55 go
56 create table t1(Name nvarchar(50),Subject nvarchar(50),Result int)
57 insert t1 select 'a','a1',80
58 union all select 'a','a2',90
59 union all select 'a','a3',85
60 union all select 'b','a1',85
61 union all select 'b','a2',92
62 union all select 'b','a3',82
63 go
64 select * from t1
65 go
66 --一条SQL语句得出
67 select Name,
68 语文=Sum(Case when Subject='a1' then Result end),
69 数学=Sum(Case when Subject='a2' then Result end),
70 物理=Sum(Case when Subject='a3' then Result end)
71 from t1
72 group by Name
73
74 go
75 --动态SQL1
76 --如果不知道科目(即科目是动态的)
77 DECLARE @S VARCHAR (1000)
78 SET @S='select Name'
79 select @S= @S+',SUM(CASE subject WHEN '''+subject+''' THEN Result END) AS ['+subject+']'
80 FROM (SELECT distinct subject from t1) bb
81 SET @S= @S+' from t1 group by Name'
82 exec(@S)
83 --select Name,SUM(CASE subject WHEN 'a1' THEN Result END) AS [a1],SUM(CASE subject WHEN 'a2' THEN Result END) AS [a2],SUM(CASE subject WHEN 'a3' THEN Result END) AS [a3] from t1 group by Name
84
85 --动态SQL2
86 declare @sql varchar(8000)
87 set @sql = 'select Name,'
88 select @sql = @sql +quotename(Subject) + '= isnull(Sum(Case when Subject='''+Subject+''' then Result end),0),' --给出判断当某些字段下有Null时会给0
89 from t1 group by Subject
90 select @sql = @sql + ' sum(Result) total from t1 group by Name'
91 exec(@sql)
92 --select Name,[a1]= isnull(Sum(Case when Subject='a1' then Result end),0),[a2]= isnull(Sum(Case when Subject='a2' then Result end),0),[a3]= isnull(Sum(Case when Subject='a3' then Result end),0), sum(Result) total from t1 group by Name
93
94 --======================做统计===========================================
95 -- 1日 2日 3日 4日 5日 6日 7日 8日 9日 10日//日期
96 -- 1 1 2 2 2 8 9 1 9 1
97 -- 1 3 3 2 2 8 3 9 1 9
98 -- ..
99 --我想统计:1-5日,6-10日的累加值得下表
100 --1-5日 6-10日
101 -- 8 28
102 -- 11 30
103 if object_id('T1') is not null
104 drop table T1
105 go
106 create table T1([1日] int, [2日] int, [3日] int, [4日] int, [5日] int, [6日] int, [7日] int, [8日] int, [9日] int, [10日] int)
107
108 insert T1 select 1, 1, 2, 2, 2, 8, 9, 1, 9, 1
109 union all select 1, 3, 3, 2, 2, 8, 3, 9, 1, 9
110 go
111 select * from T1
112 go
113
114 select [1日]+ [2日]+ [3日] + [4日]+ [5日] as [1-5日] from T1
115 --=======================字段的累加================
116 --内容是'82,65,32,98',也就是说,这个字段里面的数字是用","隔开的
117 --,现在我想把这里面的数字取出来,并累加,想要得到它的累加值结果为"277"
118 go
119 if object_id('T1') is not null
120 drop table T1
121 go
122 CREATE TABLE T1(id INT,string VARCHAR(100))
123 INSERT T1
124 SELECT 1,'82,65,32,98' UNION ALL
125 SELECT 2,'10,20,30,40'
126 go
127 select * from T1
128 go
129 --建临时表的语法---
130 if object_id('A') IS NOT NULL
131 drop table A
132 go
133 CREATE TABLE A(id INT,string VARCHAR(100))
134 INSERT A
135 SELECT 1,'82,65,32,98' UNION ALL
136 SELECT 2,'10,20,30,40'
137
138 SELECT * FROM A
139 --建立辅助临时表
140 --=================================================
141 if object_id('#1') is not null
142 drop table #1
143 go
144 SELECT TOP 8000 id = identity(int,1,1)
145 INTO #1 FROM syscolumns a, syscolumns b
146
147 --执行查询
148 SELECT A.ID, Num = CAST(SUBSTRING(A.string, B.ID, CHARINDEX(',', A.string + ',', B.ID) - B.ID) AS INT)
149 INTO #2
150 FROM A, #1 B
151 WHERE SUBSTRING(',' + a.string, B.id, 1) = ','
152 GO
153 if object_id('#2') is not null
154 drop table #2
155 SELECT ID,Total=SUM(CAST(Num AS INT))
156 FROM #2
157 GROUP BY ID
158 --=========================================================
159 go
160 drop table A
161 go
162 DECLARE @str varchar(1000)
163 SET @str = '82,65,32,98'
164
165 DECLARE @re int
166 DECLARE @s nvarchar(4000)
167 SET @s = 'SET @re=' + REPLACE(@str, ',', '+')
168 EXEC sp_executesql @s, N'@re int OUT', @re OUT
169 SELECT @re
170
171 --======================================
172
173 go
174 --=======================按月做统计报表================================
175 --有表如下:
176 --id workdate ondutyName
177 --1 2006-1-1 a;b;
178 --2 2006-1-2 b;c;
179 --3 2006-1-3 a;c;
180 --.
181 --workdate表示值班日期,ondutyName表示值班人员,以';'隔开不同的人员,
182 --现在要得到这样的统计结果:
183 --比如统计2006年1月每天的值班情况,得到以下的数据:
184 --Name 1 2 3 .31
185 --a 1 0 1 .
186 --b 1 1 0 .
187 --c 0 1 1 .
188 --如果a这天值班了,就用1表示,不值班,就用0表示
189 --如果统计的是2006年2月数据,因为2月只有28天,那么,生成的统计表的格式就如下:
190 --Name 1 2 3 28
191 --a .
192 --b .
193 --c .
194 --请问该怎样写这样的存储过程?
195 go
196 if object_id('t1') is not null
197 drop table t1
198 go
199 create table t1(id int identity(1,1),workdate datetime,ondutyName varchar(50))
200 insert t1 select '2006-1-1','a;b;'
201 union all select '2006-1-2','b;c;'
202 union all select '2006-1-3','c;d;'
203 union all select '2006-1-4','d;e;'
204 union all select '2006-1-5','a;c;'
205 union all select '2006-1-6','g;b;'
206 union all select '2006-1-7','e;c;'
207 union all select '2006-1-8','b;d;'
208 go
209 select * from t1
210 go
211 --用动态SQL
212 select top 3000 identity(int,1,1)[id] into # from sysobjects a, sysobjects b
213 go
214 select substring(ondutyname+';',b.id,CHARINDEX(';',ondutyname+';',b.id)-b.id)Name,
215 day(workdate)workdate
216 into #t
217 from (select * from t1 where workdate BETWEEN '2006-1-1' and '2006-1-31') a,# b
218 where substring(';'+ondutyname,b.id,1)=';'
219 go
220
221 declare @table varchar(1000)
222 set @table='select Name,'
223 select @table=@table+'(case when((select workdate from #t b where b.name=a.name and b.workdate='+
224 QUOTENAME(workdate,'''')+'))is null then 0 else 1 end) as '+QUOTENAME(workdate)+','
225 from #t
226 group by workdate
227 set @table = left(@table,len(@table)-1)+' from #t a'
228 exec (@table)
229 go
230 ---=================================
231 --
232 --Year Quarter Amount
233 --2000 1 1.1
234 --2000 2 1.2
235 --2000 3 1.3
236 --2000 4 1.4
237 --2001 1 2.1
238 --2001 2 2.2
239 --2001 3 2.3
240 --2001 4 2.4
241 --其中每行表表示一个季度的数据。
242 --
243 --如果处理表A中的数据,得到如下的结果。
244 --Year Quarter1 Quarter2 Quarter3 Quarter4
245 --2000 1.1 1.2 1.3 1.4
246 --2001 2.1 2.2 2.3 2.4
247 --请用SQL写一段代码实现。
248 go
249 if object_id('T1') is not null
250 drop table T1
251 go
252 create table T1
253 (
254 year int,
255 Quarter varchar(30),
256 amount float
257 )
258 go
259 insert T1 select 2000,'1',1.1
260 insert T1 select 2000,'2',1.2
261 insert T1 select 2000,'3',1.3
262 insert T1 select 2000,'4',1.4
263 insert T1 select 2001,'1',2.1
264 insert T1 select 2001,'2',2.2
265 insert T1 select 2001,'3',2.3
266 insert T1 select 2001,'4',2.4
267 insert T1 select 2001,'5',2.5
268 go
269 select * from T1
270 delete from t1 where Quarter='5'
271 go
272 --SQL得出结果
273 select [Year],
274 Quarter1=Sum(Case when Quarter = '1' then Amount end),
275 Quarter2=Sum(Case when Quarter = '2' then Amount end),
276 Quarter3=Sum(Case when Quarter = '3' then Amount end),
277 Quarter4=Sum(Case when Quarter = '4' then Amount end)
278 from T1
279 group by [Year]
280 --动态SQL
281 --但数据当不是固定的
282 declare @sql varchar(5000)
283 set @sql = 'select [Year],'
284 select @sql = @sql + 'Sum(Case when Quarter = '''+T.Quarter+''' then Amount else 0 end) as Quarter' + T.Quarter +','
285 from (select Quarter from T1 group by Quarter) T
286 set @sql =left (@sql,len(@sql)-1) + ' from T1 group by Year'
287 print @sql
288 go
289 --select [Year],Sum(Case when Quarter = '1' then Amount else 0 end) as Quarter1,Sum(Case when Quarter = '2' then Amount else 0 end) as Quarter2,Sum(Case when Quarter = '3' then Amount else 0 end) as Quarter3,Sum(Case when Quarter = '4' then Amount else 0 end) as Quarter4,Sum(Case when Quarter = '5' then Amount else 0 end) as Quarter5 from T1 group by Year
290 --============================================实用的SQL
291 if object_id('bb') is not null
292 drop table bb
293 go
294 CREATE TABLE [bb] (
295 [prsa] [int] NULL ,
296 [prend] [int] NULL ,
297 [type] [char] (2) NULL
298 ) ON [PRIMARY]
299 go
300 insert bb select 12,213,'D'
301 union all select 214,300,'D+'
302 union all select 301,413,'C'
303 union all Select 414,500,'C+'
304 union all select 501,613,'B'
305 union all select 614,700,'B+'
306 union all select 701,800,'A'
307 go
308 select * from bb
309 GO
310 if object_id('aa') is not null
311 drop table aa
312 go
313 CREATE TABLE [aa] (
314 [name] [nvarchar] (20) NULL ,
315 [pr] [int] NULL
316 ) ON [PRIMARY]
317 GO
318 insert aa select N'小1',521
319 union all select N'王2',321
320 union all select N'李3',152
321 union all select N'李4',132
322 go
323 select * from aa
324 --===========评出aa表中学生的等级(aa的表数据不固定)============================
325 select aa.name,bb.type from aa inner join bb on aa.pr between bb.prsa and bb.prend
326
327 --===========评出bb表中各等级学生数(即打A的有多少学生,打B的有多少学生)============================
328
329 --第一种方法
330 SELECT type,isnull(sum(cn),0) FROM bb b
331 left join (select 1 as cn,sum(pr)as prr from aa group by name) a
332 on (a.prr BETWEEN b.prsa and b.prend)
333 group by type
334 --第二种方法
335 select bb.type, count(pr) 小计 from bb left join aa on aa.pr between bb.prsa and bb.prend group by bb.type
336 --=====================评出bb表中各等级学生有哪些===================
337 if object_id('fun') is not null
338 drop function fun
339 go
340 create function fun(@prsa int, @prend int)
341 returns varchar(1000)
342 as
343 begin
344 declare @re varchar(1000)
345 set @re=''
346 select @re=@re+','+name from aa where pr between @prsa and @prend
347
348 return(stuff(@re, 1, 1, ''))
349 end
350 go
351
352 select
353 bb.type,
354 [count]=count(pr),
355 [name]=dbo.fun(prsa, prend)
356 from bb
357 left join aa on aa.pr between bb.prsa and bb.prend
358 group by bb.type, bb.prsa, bb.prend
359
360 select name,等级=max(case when pr between prsa and prend then type else null end) from aa a, bb b
361 group by name
362 --2:
363 select 等级=type,个数=sum(case when pr between prsa and prend then 1 else 0 end) from bb b,aa a
364 group by type
365 --3:
366 select * from
367 (
368 select 等级=type,个数=sum(case when pr between prsa and prend then 1 else 0 end) from bb b,aa a
369 group by type
370 ) ta left join
371 (
372 select name,等级=max(case when pr between prsa and prend then type else null end) from aa a, bb b
373 group by name
374 ) tb
375 on ta.等级=tb.等级
376
377
378
379 --===========评出aa表中学生的等级(aa的表数据不固定)============================
380 select aa.*, bb.type from aa
381 join bb on aa.pr between bb.prsa and bb.prend
382
383 --===========评出bb表中各等级学生数(即打A的有多少学生,打B的有多少学生)============================
384 select type,isnull(sum(cn),0)[count] from bb
385 left join (select 1 cn,* from aa)aa on aa.pr between bb.prsa and bb.prend
386 group by type
387
388 --=====================评出bb表中各等级学生有哪些===================
389 select bb.type,aa.* from bb
390 left join aa on aa.pr between bb.prsa and bb.prend
391
392
393
394 --======================汇总SQL
395 --表1
396 --入库时间 品名 数量 人员代码 单位 状态
397 --2007-01-01 AAAA 100 111 aaa 0
398 --2007-01-01 AAAA 20 111 bbb 0
399 --2007-01-01 BBBB 100 111 aaa 0
400 --2007-01-01 AAAA 100 222 aaa 1
401 --
402 --表2
403 --入库时间 品名 数量 人员代码 单位 状态
404 --2007-01-01 AAAA 100 111 aaa 0
405 --2007-01-01 AAAA 20 111 bbb 0
406 --2007-01-01 BBBB 100 111 aaa 0
407 --2007-01-01 AAAA 100 222 aaa 1
408 --
409 --表3
410 --人员代码 姓名
411 --111 张三
412 --222 李四
413 --
414 --汇总表1与表2中品名为AAAA,单位为aaa,状态是0的数量,并且显示姓名。
415
416 if object_id('A') is not null
417 drop table A
418 go
419 create table A(入库时间 datetime, 品名 varchar(10), 数量 int, 人员代码 int, 单位 varchar(10), 状态 bit)
420 insert A select '2007-01-01', 'AAAA', 100, 111, 'aaa', 0
421 union all select '2007-01-01', 'AAAA', 20, 111, 'bbb', 0
422 union all select '2007-01-01', 'BBBB', 100, 111, 'aaa', 0
423 union all select '2007-01-01', 'AAAA', 100, 222, 'aaa', 1
424 go
425 if object_id('B') is not null
426 drop table B
427 go
428 create table B(入库时间 datetime, 品名 varchar(10), 数量 int, 人员代码 int, 单位 varchar(10), 状态 bit)
429 insert B select '2007-01-01', 'AAAA', 100, 111, 'aaa', 0
430 union all select '2007-01-01', 'AAAA', 20, 111, 'bbb', 0
431 union all select '2007-01-01', 'BBBB', 100, 111, 'aaa', 0
432 union all select '2007-01-01', 'AAAA', 100, 222, 'aaa', 1
433
434 create table C(人员代码 int, 姓名 varchar(10))
435 insert C select 111, '张三'
436 union all select 222, '李四'
437
438 select 'AAAA'品名,'aaa'单位,(select 姓名 from c where c.人员代码=a.人员代码),sum(数量)
439 from(select * from a where 品名='AAAA' and 单位='aaa' and 状态='0'
440 union all select * from a where 品名='AAAA' and 单位='aaa' and 状态='0')a
441 group by 人员代码
442
443 go
444 drop table A
445 drop table B
446 go
447 ----id name count time
448 --1 a 12 2007-2-7
449 --2 b 13 2007-2-7
450 --3 c 4 2007-2-7
451 --4 d 15 2007-2-7
452 --5 e 7 2007-2-7
453 --6 a 21 2007-2-8
454 --7 b 33 2007-2-8
455 --8 c 11 2007-2-8
456 --9 d 65 2007-2-8
457 --10 e 10 2007-2-8
458 --
459 --期望结果:
460 -- 2007-2-7 2007-2-8
461 --a 12 21
462 --b 13 33
463 --c 4 11
464 --d 15 65
465 --e 7 10
466 if object_id('t') is not null
467 drop table t
468 go
469 create table t(id int,[name] varchar(50),ount int,time datetime)
470 insert t select 1, 'a', '12', '2007-2-7'
471 union all select 2, 'b', '13', '2007-2-7'
472 union all select 3, 'c', '4', '2007-2-7'
473 union all select 4, 'd', '15', '2007-2-7'
474 union all select 5, 'e', '7', '2007-2-7'
475 union all select 6, 'a', '21', '2007-2-8'
476 union all select 7, 'b' , '33', '2007-2-8'
477 union all select 8, 'c', '11', '2007-2-8'
478 union all select 9, 'd', '65', '2007-2-8'
479 union all select 10, 'e', '10', '2007-2-8'
480 go
481 select * from t
482 go
483 declare @sql varchar(8000)
484 set @sql = 'select name,'
485 select @sql = @sql + quotename(convert(varchar(50),t1.time,110)) + '=sum(case when time = '''+convert(varchar(50),t1.time,110)+''' then ount end),'
486 from (select time from t group by time) t1
487 set @sql = left(@sql,len(@sql)-1) + ' from t group by name'
488 exec @sql
489
490 go
491 declare @sql varchar(8000)
492 set @sql = 'select name'
493 select @sql = @sql + ',sum(case when time = '''+convert(varchar(50),t1.time,110)+''' then ount end) ['+convert(varchar(10),[time],120)+']'
494 from (select distinct time from t group by time) t1
495 set @sql = @sql + 'from t group by name'
496 print @sql
497 go
498
499 declare @sql varchar(8000)
500 set @sql='select name'
501 select @sql=@sql+',sum(case time when '''+convert(varchar(10),[time],120)+''' then [ount] end) ['+convert(varchar(10),[time],120)+']' from (select distinct [time] from t) a
502 select @sql=@sql+' from t group by name'
503 print @sql
504 --exec(@sql)
505
506
青华木园