1 /*
2
3
4 2006年10月01日
5
6 SQL Server 数据库的高级操作
7 (1) 批处理
8 (2) 变量
9 (3) 逻辑控制
10 (4) 视图
11 (5) 函数
12 (6) 高级查询
13
14 */
15
16 (1)批处理
17 将多条SQL语句作为一个整体去编译,生成一个执行计划,然后,执行!
18 理解批处理的关键在于"编译",对于由多条语句组成的一个批处理,
19 如果在编译时,其中,有一条出现语法错误,将会导致编译失败!
20
21 create table t
22 (
23 a int,
24 b int
25 )
26
27 -- 注释
28 -- 如果多行注释中包含了批处理的标识符go
29 -- 在编译的过程中代码将会被go分割成多个部分来分批编译
30 -- 多行注释的标记将会被分隔而导致编译出错
31 -- 以下几条语句是三个非常经典的批处理
32 -- 你猜一下会添加几条记录!
33 /*
34 insert into t values (1,1)
35 go
36 */
37 insert into t values (2,2)
38 go
39 /*
40 insert into t values (3,3)
41 */
42 go
43
44
45 -- 查询看添加了几条记录
46 select * from t
47
48 truncate table t
49
50 (2)变量
51
52 -- 全局变量
53 SQL Server中全局变量由系统定义、系统维护,用户一般仅可对其进行读取!
54
55 -- 查看SQL Server版本
56 print @@version
57
58 -- 服务器名称
59 print @@servername
60
61 -- 系统错误编号
62 insert into t values ('a','a')
63 print @@error
64
65 insert into t values ('a','a')
66 if @@error = 245
67 print 'Error'
68
69 -- SQL Server 版本的语言信息
70 print @@LANGUAGE
71
72 -- 一周的第一天从星期几算起
73 print @@datefirst
74
75 -- CPU 执行命令所耗费时间的累加
76 print @@cpu_busy
77
78 -- 获取最近添加的标识列的值
79 create table tt
80 (
81 a int identity(3, 10),
82 b int
83 )
84 insert into tt (b) values (1)
85 print @@identity
86 select * from tt
87
88 -- 局部变量
89 局部变量由用户定义,仅可在同一个批处理中调用和访问
90
91 declare @intAge tinyint
92 set @intAge = 12
93 print @intAge
94
95 declare @strName varchar(12)
96 select @strName = 'state'
97 print @strName
98 select au_lname, @strName from authors
99
100 (3)逻辑控制
101
102 -- IF条件判断
103 declare @i int
104 set @i = 12
105 if (@i > 10)
106 begin -- {
107 print 'Dadadada!'
108 print 'Dadadada!'
109 end -- }
110 else
111 begin
112 print 'XiaoXiao!'
113 print 'XiaoXiao!'
114 end
115
116 -- While循环控制
117 declare @i int;
118 set @i = 12;
119 print @i
120 --return;
121 while (@i < 18)
122 begin
123 print @i;
124 set @i = @i + 1;
125 if @i < 17
126 continue;
127 if @i > 15
128 break;
129 end;
130 print @i
131
132 -- CASE 分支判断
133 select au_lname, state, '犹他州' from authors where state = 'UT'
134 select au_lname, state, '密西西比州' from authors where state = 'MI'
135 select au_lname, state, '肯塔基州' from authors where state = 'KS'
136
137 select au_lname, state,
138 case state
139 when 'UT' then '犹他州'
140 when 'MI' then '密西西比州'
141 when 'KS' then '肯塔基州'
142 when 'CA' then '加利福利亚'
143 else state
144 end
145 from authors
146
147
148 (3)视图
149 -- Northwind 数据库中Employees表
150 -- 创建视图显示每个员工的编号(EmployeeID)、姓(FirstName)、名(LastName)以及上级(ReportsTo)的姓
151 use northwind
152 go
153
154 -- 注意:字段ReportsTo指代了每个员工的上级的编号
155 select EmployeeID, FirstName, LastName, ReportsTo
156 from employees
157 go
158
159 -- 寻找每个员工的上级
160 -- 子查询
161 select emp.EmployeeID, emp.FirstName, emp.LastName,
162 (select mag.FirstName from employees as mag where emp.ReportsTo = mag.EmployeeID ) as ManagerFirstName
163 from employees as emp
164 go
165
166
167
168
169
170 (4.1)系统函数
171
172 -- 获取指定字符串中左起第一个字符的ASC码
173 print ascii('ABCDEF')
174 -- 根据给定的ASC码获取相应的字符
175 print char(65)
176 -- 获取给定字符串的长度
177 print len('abcdef')
178 -- 大小写转换
179 print lower('ABCDEF')
180 print upper('abcdef')
181 -- 去空格
182 print ltrim(' abcd dfd df ')
183 print rtrim(' abcd dfd df ')
184 -- 求绝对值
185 print abs(-12)
186 -- 幂
187 -- 3 的 2 次方
188 print power(3,2)
189 print power(3,3)
190 -- 随机数
191 -- 0 - 1000 之间的随机数
192 print rand() * 1000
193 -- 获取圆周率
194 print pi()
195
196
197 -- 获取系统时间
198 print getdate()
199
200 -- 获取3天前的时间
201 print dateadd(day, -3 , getdate())
202 -- 获取3天后的时间
203 print dateadd(day, 3 , getdate())
204 -- 获取3年前的时间
205 print dateadd(year, -3 , getdate())
206 -- 获取3年后的时间
207 print dateadd(year, 3 , getdate())
208
209 -- 获取3月后的时间
210 print dateadd(month, 3 , getdate())
211 -- 获取9小时后的时间
212 print dateadd(hour, 9 , getdate())
213 -- 获取9分钟后的时间
214 print dateadd(minute, 9 , getdate())
215
216 -- 获取指定时间之间相隔多少年
217 print datediff(year, '2005-01-01', '2008-01-01')
218 -- 获取指定时间之间相隔多少月
219 print datediff(month, '2005-01-01', '2008-01-01')
220 -- 获取指定时间之间相隔多少天
221 print datediff(day, '2005-01-01', '2008-01-01')
222
223 -- 字符串合并
224 print 'abc' + 'def'
225
226 print 'abcder'
227
228 print 'abc' + '456'
229 print 'abc' + 456
230
231 -- 类型转换
232 print 'abc' + convert(varchar(10), 456)
233
234 select title_id, type, price from titles
235 -- 字符串连接必须保证类型一致(以下语句执行将会出错)
236 -- 类型转换
237 select title_id + type + price from titles
238 -- 正确
239 select title_id + type + convert(varchar(10), price) from titles
240
241 print '123' + convert(varchar(3), 123)
242 print '123' + '123'
243
244 print convert(varchar(12), '2005-09-01',110)
245
246 -- 获取指定时间的特定部分
247 print year(getdate())
248 print month(getdate())
249 print day(getdate())
250
251 -- 获取指定时间的特定部分
252 print datepart(year, getdate())
253 print datepart(month, getdate())
254 print datepart(day, getdate())
255 print datepart(hh, getdate())
256 print datepart(mi, getdate())
257 print datepart(ss, getdate())
258 print datepart(ms, getdate())
259
260 -- 获取指定时间的间隔部分
261 -- 返回跨两个指定日期的日期和时间边界数
262 print datediff(year, '2001-01-01', '2008-08-08')
263 print datediff(month, '2001-01-01', '2008-08-08')
264 print datediff(day, '2001-01-01', '2008-08-08')
265 print datediff(hour, '2001-01-01', '2008-08-08')
266 print datediff(mi, '2001-01-01', '2008-08-08')
267 print datediff(ss, '2001-01-01', '2008-08-08')
268
269 -- 在向指定日期加上一段时间的基础上,返回新的 datetime 值
270 print dateadd(year, 5, getdate())
271 print dateadd(month, 5, getdate())
272 print dateadd(day, 5, getdate())
273 print dateadd(hour, 5, getdate())
274 print dateadd(mi, 5, getdate())
275 print dateadd(ss, 5, getdate())
276
277 -- 其他
278 print host_id()
279 print host_name()
280 print db_id('pubs')
281 print db_name(5)
282
283
284 -- 利用系统函数作为默认值约束
285 drop table ttt
286
287 create table ttt
288 (
289 stu_name varchar(12),
290 stu_birthday datetime default (getdate())
291 )
292
293 alter table ttt
294 add constraint df_ttt_stu_birthday default (getdate()) for stu_birthday
295
296 insert into ttt values ('ANiu', '2005-04-01')
297 insert into ttt values ('ANiu', getdate())
298
299 insert into ttt values ('AZhu', default)
300
301 sp_help ttt
302
303 select * from ttt
304
305
306
307 (4.2)自定义函数
308
309 select title_id
310 from titles
311 where type = 'business'
312
313 select stuff(title_id,1,3,'ABB'), type
314 from titles
315 where type = 'business'
316
317 select count(title_id) from titles where type = 'business'
318 select title_id from titles where type = 'business'
319
320
321 select *,count(dbo.titleauthor.title_id)
322 FROM dbo.authors INNER JOIN
323 dbo.titleauthor ON dbo.authors.au_id = dbo.titleauthor.au_id
324
325 select au_id, count(title_id)
326 from titleauthor
327 group by au_id
328
329 SELECT dbo.authors.au_id, COUNT(dbo.titleauthor.title_id) AS '作品数量'
330 FROM dbo.authors left outer JOIN
331 dbo.titleauthor ON dbo.authors.au_id = dbo.titleauthor.au_id
332 GROUP BY dbo.authors.au_id
333 order by '作品数量'
334
335 -- 自定义函数的引子(通过这个子查询来引入函数的作用)
336
337 -- 子查询
338 -- 统计每个作者的作品数
339 -- 将父查询中的作者编号传入子查询
340 -- 作为查询条件利用聚合函数count统计其作品数量
341 select au_lname,
342 (select count(title_id)
343 from titleauthor as ta
344 where ta.au_id = a.au_id
345 ) as TitleCount
346 from authors as a
347 order by TitleCount
348
349
350
351
352 -- 是否可以定义一个函数
353 -- 将作者编号作为参数统计其作品数量并将其返回
354 select au_id, au_lname, dbo.GetTitleCountByAuID(au_id) as TitleCount
355 from authors
356 order by TitleCount
357
358 -- 根据给定的作者编号获取其相应的作品数量
359 create function GetTitleCountByAuID(@au_id varchar(12))
360 returns int
361 begin
362 return (select count(title_id)
363 from titleauthor
364 where au_id = @au_id)
365 end
366
367
368 -- 利用函数来显示每个作者的作品数量
369 create proc pro_CalTitleCount
370 as
371 select au_id, au_lname, dbo.GetTitleCountByAuID(au_id) as TitleCount
372 from authors
373 order by TitleCount
374 go
375
376 -- 执行存储过程
377 execute pro_CalTitleCount
378
379 -- vb中函数定义格式
380 function GetTitleCountByAuID(au_id as string) as integer
381
382 .......
383
384 GetTitleCountByAuID = ?
385 end function
386
387 -- SALES 作品销售信息
388 select * from sales
389
390 -- 根据书籍编号查询其销售记录(其中,qty 表示销量)
391 select * from sales where title_id = 'BU1032'
392
393 -- 根据书籍编号统计其总销售量(其中,qty 表示销量)
394 select sum(qty) from sales where title_id = 'BU1032'
395
396 -- 利用分组语句(group by),根据书籍编号统计每本书总销售量(其中,qty 表示销量)
397 select title_id, sum(qty) from sales group by title_id
398
399 -- 是否可以考虑定义一个函数根据书籍编号来计算其总销售量
400 -- 然后,将其应用到任何一条包含了书籍编号的查询语句中
401 select title_id, title, dbo.GetTotalSaleByTitleID(title_id) as TotalSales
402 from titles
403 order by TotalSales
404
405 -- 定义一个函数根据书籍编号来计算其总销售量
406 create function GetTotalSaleByTitleID(@tid varchar(24))
407 returns int
408 begin
409 return(select sum(qty) from sales where title_id = @tid)
410 end
411
412 select count(title_id) + 1
413 from titles
414 where dbo.GetTotalSaleByTitleID(title_id) > dbo.GetTotalSaleByTitleID('pc1035')
415
416 -- 删除函数
417 drop function GetRankByTitleId
418
419 -- 根据书籍编号计算其销量排名
420 create function GetRankByTitleId(@tid varchar(24))
421 returns int
422 begin
423 return (select count(title_id) + 1
424 from titles
425 where dbo.GetTotalSaleByTitleID(title_id) > dbo.GetTotalSaleByTitleID(@tid))
426 end
427
428 -- 统计书籍销量的前10位
429 -- 其中,可以利用函数计算结果的别名作为排序子句的参照列
430 select top 10 title_id, title, dbo.GetTotalSaleByTitleID(title_id) as TotalSales
431 from titles
432 order by TotalSales desc
433
434 -- 书籍销量排名视图
435 create view viewToalSales
436 as
437 select title_id, title, dbo.GetTotalSaleByTitleID(title_id) as TotalSales
438 from titles
439 go
440
441 select * from viewToalSales;
442
443 -- 根据书籍编号计算其销量排名
444 create function GetTheRankOfTitle(@id varchar(20))
445 returns int
446 begin
447 return(select count(TotalSales) + 1
448 from viewToalSales
449 where TotalSales > dbo.GetTotalSaleByTitleID(@id))
450 end
451
452 -- 根据书籍编号计算其销量排名
453 select dbo.GetTheRankOfTitle('pc1035') from titles
454
455 -- 在查询语句中利用函数统计每本书的总销量和总排名
456 select title_id, title,
457 dbo.GetTotalSaleByTitleID(title_id) as TotalSales,
458 dbo.GetRankByTitleId(title_id) as TotalRank
459 from titles
460 order by TotalSales desc
461
462 -- 查看表结构
463 sp_help titles
464 -- 查看存储过程的定义内容
465 sp_helptext GetRankByTitleId
466 sp_helptext sp_helptext
467 sp_helptext xp_cmdshell
468
469
470 -- [ORDER DETAILS] 订单详细信息
471 select * from [order details]
472 select * from [order details] where productid = 23
473 -- 根据产品编号在订单详细信息表中统计总销售量
474 select sum(quantity) from [order details] where productid = 23
475
476 -- 构造一个函数根据产品编号在订单详细信息表中统计总销售量
477 create function GetTotalSaleByPID(@Pid varchar(12))
478 returns int
479 begin
480 return(select sum(quantity) from [order details] where productid = @Pid)
481 end
482
483
484 select * from products
485 -- 在产品表中查询,统计每一样产品的总销量
486 select productid, productname, dbo.GetTotalSaleByPID(productid) from products
487
488
489 --
490 CREATE FUNCTION LargeOrderShippers ( @FreightParm money )
491 RETURNS @OrderShipperTab TABLE
492 (
493 ShipperID int,
494 ShipperName nvarchar(80),
495 OrderID int,
496 ShippedDate datetime,
497 Freight money
498 )
499 AS
500 BEGIN
501 INSERT @OrderShipperTab
502 SELECT S.ShipperID, S.CompanyName,
503 O.OrderID, O.ShippedDate, O.Freight
504 FROM Shippers AS S INNER JOIN Orders AS O
505 ON S.ShipperID = O.ShipVia
506 WHERE O.Freight > @FreightParm
507 RETURN
508 END
509
510 SELECT * FROM LargeOrderShippers( $500 )
511
512
513 -- 根据作者编号计算其所得版权费
514 create function fun_RoyalTyper ( @au_id id)
515 returns int
516 as
517 begin
518 declare @rt int
519 select @rt = sum(royaltyper) from titleauthor where au_id = @au_id
520 return (@rt)
521 end
522 go
523
524 select top 1 au_lname, au_fname, dbo.fun_RoyalTyper(au_id) as '版权费'
525 from authors
526 order by dbo.fun_RoyalTyper(au_id) desc
527 go
528
529 create function fun_MaxRoyalTyper_Au_id ()
530 returns id
531 as
532 begin
533 declare @au_id id
534 select @au_id = au_id
535 from authors
536 order by dbo.fun_RoyalTyper(au_id)
537 return(@au_id)
538 end
539 go
540
541 select dbo.fun_MaxRoyalTyper_Au_id()
542 go
543
544
545 select au_lname, au_fname, dbo.fun_RoyalTyper(au_id) as '版权税'
546 from authors
547 where au_id = dbo.fun_MaxRoyalTyper_Au_id()
548 go
549
550 (5)高级查询
551
552
553
554 select title_id, price from titles
555
556 -- 查找最高价格
557 select max(price) from titles
558
559 -- 查找最贵书籍的价格(排序),如果存在多本价格最贵的书,此方法将会遗漏
560 select top 1 title_id, price
561 from titles
562 order by price desc
563
564 -- 查找最贵书籍的价格(子查询)
565 select title_id, price
566 from titles
567 where price = (select max(price) from titles)
568
569 -- 查询指定出版社出版的书(连接)
570 select p.pub_name as '出版社', t.title as '书籍名称'
571 from publishers as p join titles as t on p.pub_id = t.pub_id
572 where pub_name = 'New Moon Books'
573
574 -- 查询指定出版社出版的书(子查询)
575 select title
576 from titles
577 where pub_id = (select pub_id
578 from publishers
579 where pub_name = 'New Moon Books')
580
581 -- 查询指定出版社出版的书(分开查询)
582 select title from titles where pub_id = '0736'
583
584 select pub_id
585 from publishers
586 where pub_name = 'New Moon Books'
587
588
589 -- 重点
590 -- 理解相关子查询的基础
591 --
592 select * from titles where type = 'business'
593 select * from titles where type = 'business123'
594
595 select * from titles where 1 = 1
596
597 -- 在订单表中寻找满足以下条件的订单编号以及相应的客户编号
598 -- 在详细订单表中存在对应的订单编号并且其中包含产品编号为23的产品
599 -- 然后将产品编号为23的产品订购量返回判断是否大于20
600 USE northwind
601
602 SELECT orderid, customerid
603 FROM orders AS or1
604 WHERE 20 < (SELECT quantity FROM [order details] AS od
605 WHERE or1.orderid = od.orderid
606 AND od.productid = 23)
607 GO
608
609 SELECT au_lname, au_fname
610 FROM authors
611 WHERE 100 IN
612 (
613 SELECT royaltyper FROM titleauthor
614 WHERE titleauthor.au_ID = authors.au_id
615 )
616
617 select authors.au_lname,authors.au_fname
618 from authors join titleauthor on titleauthor.au_ID=authors.au_id
619 where titleauthor.royaltyper =100
620
621 USE pubs
622
623 SELECT au_lname, au_fname
624 FROM authors
625 WHERE au_id IN
626 (SELECT au_id
627 FROM titleauthor
628 WHERE title_id IN
629 (SELECT title_id
630 FROM titles
631 WHERE type = 'popular_comp'))
632
633
634
635 select distinct t.type, a.au_lname, a.au_fname
636 from authors as a join titleauthor as ta on a.au_id = ta.au_id
637 join titles as t on ta.title_id = t.title_id
638 where t.type = 'business'
639
640 -- 查找类型为'business'或是'trad_cook'类型的书籍
641 select * from titles where type = 'business'
642 select * from titles where type = 'trad_cook'
643
644 -- 查找类型为'business'或是'trad_cook'类型的书籍(Or)
645 select * from titles
646 where type = 'business' or type = 'trad_cook'
647
648 -- 查找类型为'business'或是'trad_cook'类型的书籍(In)
649 select * from titles
650 where type in ('business', 'trad_cook')
651
652 -- 查找来自'KS'或是'UT'的作者
653 select au_lname, state from authors
654 where state = 'KS'
655 select au_lname, state from authors
656 where state = 'UT'
657
658 -- 查找来自'KS'或是'UT'的作者(Or)
659 select au_lname, state from authors
660 where state = 'UT' or state = 'KS'
661
662 -- 查找来自'KS'或是'UT'的作者(In)
663 select au_lname, state from authors
664 where state in ('UT', 'KS')
665
666 select au_lname, state from authors
667 where state not in ('UT', 'KS')
668
669
670 -- 查找出版了类型为'business'类型的书籍的出版社
671 SELECT pub_id FROM titles WHERE type = 'business'
672
673 SELECT pub_id,pub_name
674 FROM publishers
675 WHERE pub_id IN ('1389', '0736')
676
677
678 -- 查找出版了类型为'business'类型的书籍的出版社(In和子查询)
679 SELECT pub_id,pub_name
680 FROM publishers
681 WHERE pub_id IN
682 (SELECT pub_id
683 FROM titles
684 WHERE type = 'business')
685
686
687
688 SELECT title, advance
689 FROM titles
690 WHERE advance >
691 (
692 SELECT MAX(advance)
693 FROM publishers INNER JOIN titles ON
694 titles.pub_id = publishers.pub_id
695 WHERE pub_name = 'Algodata Infosystems'
696 )
697
698
699 SELECT title, advance
700 FROM titles
701 WHERE advance > all
702 (
703 SELECT advance
704 FROM publishers INNER JOIN titles ON
705 titles.pub_id = publishers.pub_id
706 WHERE pub_name = 'Algodata Infosystems'
707 and advance is not null
708 )
709
710
711 declare @i int
712 set @i = 12
713 if @i < null
714 print 'DDDDD'
715 else
716 print 'XXXXX'
717
718
719
720
721
722
723
724 SELECT advance
725 FROM publishers INNER JOIN titles ON
726 titles.pub_id = publishers.pub_id
727 WHERE pub_name = 'Algodata Infosystems'
728
729
730
731
732 select title_id, price from titles
733 where price > all
734 (
735 select price from titles where type = 'business'
736 )
737
738 select title_id, price from titles
739 where price >
740 (
741 select max(price) from titles where type = 'business'
742 )
743
744 select title_id, price from titles
745 where price > any
746 (
747 select price from titles where type = 'business'
748 )
749
750 select title_id, price from titles
751 where price >
752 (
753 select min(price) from titles where type = 'business'
754 )
755
756 select price from titles where type = 'business'
757
758
759 if exists(select * from titles where type = '123')
760 print 'ZZZZZ'
761 else
762 print 'BBBBB'
763
764 if exists(select * from authors
765 where city = 'Berkeley' and state ='UT')
766 print 'Welcome'
767 else
768 print 'Bye-Bye'
769
770 -- 筛选出'business'以及'trad_cook'类型的书籍(联合查询)
771 select title_id, type from titles where type = 'business'
772 union
773 select title_id, type from titles where type = 'trad_cook'
774
775 -- 统计'business'类型的书籍的总价(联合查询)
776 select title, price from titles where type = 'business'
777 union
778 select '合计:', sum(price) from titles where type = 'business'
779
780 -- 统计所有书籍的类型剔除重复(Distinct)
781 select distinct type from titles
782
783 -- 作者记录的复制(Select Into)
784 select * into au from authors
785
786 select * from au
787
788 -- 查看数据表结构(Select Into并没有对数据表的约束进行复制)
789 sp_help authors
790 sp_help au
791
792
793 -- 分页(子查询的经典应用之一)
794
795 -- Jobs 职务信息表(pubs 数据库)
796 -- 在实际项目中,显示职务信息时,而职务信息量非常庞大,可能需要将其分为若干个页面来显示
797 -- 比如:每页显示4条记录,那么,第一页将显示1,2,3,4,第二页将显示5,6,7,8。。。。。
798
799 -- 显示所有信息
800 SELECT * FROM jobs
801 -- 显示前 4 信息
802 select top 4 * from jobs
803 -- 显示前 8 信息
804 select top 8 * from jobs
805 -- 显示前 12 信息
806 select top 12 * from jobs
807
808 -- 寻找规律,每一页的信息源于前(页面大小 * 页码)条信息的反序结果的前 页面大小 条记录
809 -- 比如:第二页就是前 8 条记录的反序结果的前 4 条
810 select top 4 *
811 from (select top 8 * from jobs) as tt
812 order by job_id desc
813
814 -- 当然,对于期望按升序显示查询结果的要求可以对查询结果进行再次排序
815 select * from
816 (select top 4 *
817 from (select top 8 * from jobs) as tt
818 order by job_id desc) as stt
819 order by job_id
820
821
822 -- SQL 命令中不支持在 select 的查询列表中直接使用局部变量
823 -- 比如:select top @PageSize * from jobs
824 -- 那么,可以考虑对sql命令进行拼装,然后,利用系统存储过程 sp_executesql 来执行
825 exec sp_executesql N'Select * from jobs'
826
827 -- 存储过程的实现
828 -- 其中,@CurrentPageSize用于确定最后一页的页面大小
829 create proc proGetJobsByPage
830 @CurrentPageSize int,
831 @PageSize int,
832 @CurrentPage int
833 as
834 Declare @strSql nvarchar(400)
835 set @strSql = 'select * from
836 (select top ' + convert(nvarchar(4), @CurrentPageSize) + ' *
837 from (select top ' + convert(nvarchar(4),(@PageSize * @CurrentPage)) + ' * from jobs) as tt
838 order by job_id desc) as stt
839 order by job_id'
840 exec sp_executesql @strSql
841 go
842
843 -- 测试
844 exec proGetJobsByPage 2, 4, 4
845
846
847
848 (6)存储过程
849
850
851 -- 扩展存储过程
852
853 -- 查询系统目录下文件信息
854 xp_cmdshell 'dir *.*'
855
856 -- 启动Windows系统服务
857 xp_cmdshell 'net start iisadmin'
858
859
860
861 (7)游标
862
863 -- 游标的五个基本操作步骤:
864
865 -- 声明
866 declare cur_titles cursor
867 for
868 select title, price from titles
869
870 -- 打开
871 open cur_titles
872
873 -- 提取
874 fetch cur_titles
875
876 fetch next from cur_titles
877
878 -- 关闭
879 close cur_titles
880
881 -- 释放
882 deallocate cur_titles
883
884
885
886
887 -- 利用游标遍历所有书籍信息,通过冒泡排序法进行比较,找出最高价格的书
888 -- 这一段为批处理版
889 -- 与批处理版相比,存储过程版更方便调试以及代码的重用
890
891 -- 声明
892 declare cur_titles cursor
893 for select title, price from titles
894
895 -- 打开
896 open cur_titles
897
898 declare @title varchar(80)
899 declare @price numeric(9,4)
900
901 declare @title_temp varchar(80)
902 declare @price_temp numeric(9,4)
903
904 -- 提取
905 fetch cur_titles into @title, @price
906
907 fetch cur_titles into @title_temp, @price_temp
908
909 while @@fetch_status = 0
910 begin
911 if @price < @price_temp
912 begin
913 set @price = @price_temp
914 set @title = @title_temp
915 end
916 fetch cur_titles into @title_temp, @price_temp
917 end
918
919 -- 关闭
920 close cur_titles
921
922 -- 释放
923 deallocate cur_titles
924
925 -- 显示处理结果
926 print '最贵的书是: ' + @title + ' ' + '价格是: ' + convert(varchar(12),@price)
927 go
928
929
930 -- 定义一个存储过程
931 -- 利用游标遍历所有书籍信息,通过冒泡排序法进行比较,找出最高价格的书(游标具体应用的经典)
932 -- 这段存储过程的实现代码相对下面的实现方式略有不同
933 -- 代码重复,但是思路更清晰
934 create procedure pro_GetMaxTitle
935 as
936 -- 声明
937 declare cur_titles cursor
938 for select title, price from titles
939
940 -- 打开
941 open cur_titles
942
943 -- 存储最贵的书籍信息
944 declare @title varchar(80)
945 declare @price numeric(9,4)
946 -- 存储从游标中提取出来的书籍的信息
947 declare @title_temp varchar(80)
948 declare @price_temp numeric(9,4)
949
950 -- 提取
951 fetch cur_titles into @title, @price
952 -- 判断是否存在书籍信息
953 if @@fetch_status <> 0
954 begin
955 print '没有书籍信息!'
956 -- 关闭
957 close cur_titles
958 -- 释放
959 deallocate cur_titles
960 -- 结束存储过程
961 return
962 end
963
964 fetch cur_titles into @title_temp, @price_temp
965
966 -- 判断是否只存在一本书
967 if @@fetch_status <> 0
968 begin
969 -- 显示处理结果
970 print '最贵的书是: ' + @title + ' ' + '价格是: ' + convert(varchar(12),@price)
971 -- 关闭
972 close cur_titles
973 -- 释放
974 deallocate cur_titles
975 -- 结束存储过程
976 return
977 end
978
979
980 while @@fetch_status = 0
981 begin
982 if @price < @price_temp
983 begin
984 set @price = @price_temp
985 set @title = @title_temp
986 end
987 fetch cur_titles into @title_temp, @price_temp
988 end
989
990 -- 显示处理结果
991 print '最贵的书是: ' + @title + ' ' + '价格是: ' + convert(varchar(12),@price)
992
993 -- 关闭
994 close cur_titles
995
996 -- 释放
997 deallocate cur_titles
998
999 go
1000
1001 -- 定义一个存储过程
1002 -- 利用游标遍历所有书籍信息,通过冒泡排序法进行比较,找出最高价格的书
1003 -- 相对上面的实现方式,以下实现方式更简洁
1004 create procedure pro_GetMaxTitle
1005 as
1006 -- 声明
1007 declare cur_titles cursor
1008 for select title, price from titles
1009
1010 -- 打开
1011 open cur_titles
1012
1013 -- 存储最贵的书籍信息
1014 declare @title varchar(80)
1015 declare @price numeric(9,4)
1016 -- 存储从游标中提取出来的书籍的信息
1017 declare @title_temp varchar(80)
1018 declare @price_temp numeric(9,4)
1019
1020 -- 提取
1021 fetch cur_titles into @title, @price
1022 -- 判断是否存在书籍信息
1023 if @@fetch_status = 0
1024 begin
1025 print '没有书籍信息!'
1026 goto errNoTitles
1027 end
1028
1029 fetch cur_titles into @title_temp, @price_temp
1030 -- 判断是否只存在一本书
1031 if @@fetch_status = 0
1032 begin
1033 goto errOnlyOne
1034 end
1035
1036 while @@fetch_status = 0
1037 begin
1038 if @price < @price_temp
1039 begin
1040 set @price = @price_temp
1041 set @title = @title_temp
1042 end
1043 fetch cur_titles into @title_temp, @price_temp
1044 end
1045
1046 errOnlyOne:
1047 -- 显示处理结果
1048 print '最贵的书是: ' + @title + ' ' + '价格是: ' + convert(varchar(12),@price)
1049
1050 errNoTitles:
1051 -- 关闭
1052 close cur_titles
1053
1054 -- 释放
1055 deallocate cur_titles
1056
1057
1058 go
1059
1060
1061
1062
1063 -- 根据作者编号查看其相应的作品年销售量
1064 -- 低于5000,提示: 销售量太低
1065 -- 高于5000,提示: 销售量太高
1066 create procedure pro_sales_avg (@au_id id)
1067 as
1068 if exists(select au_id from authors where au_id = @au_id)
1069 begin
1070 declare TempSales cursor
1071 for
1072 select title, ytd_sales
1073 from titleauthor ta join titles t
1074 on ta.title_id = t.title_id
1075 where au_id = @au_id
1076
1077 open TempSales
1078
1079 declare @t varchar(80)
1080 declare @y int
1081
1082 fetch TempSales
1083 into @t, @y
1084
1085 while @@fetch_status = 0
1086 begin
1087 if 5000 > @y
1088 print @t + ' ' + convert(varchar(5),@y) + ' 销售量太低'
1089 else
1090 print @t + ' ' + convert(varchar(5),@y) + ' 销售量太高'
1091 fetch TempSales
1092 into @t, @y
1093 end
1094
1095 close TempSales
1096 deallocate TempSales
1097 end
1098 else
1099 print '作者编号无效!'
1100 go
1101
1102 exec pro_sales_avg '213-46-8915'
1103
1104
1105
1106 /*
1107 示例
1108 A. 使用简单游标和语法
1109 打开该游标时所生成的结果集包括 pubs 数据库的 authors 表中的所有行和列。可以更新该游标,对该游标所做的所有更新和删除均在提取中表现出来。因为没指定 SCROLL 选项,FETCH NEXT 是唯一可用的提取选项。
1110 */
1111
1112 DECLARE authors_cursor CURSOR
1113 FOR
1114 SELECT * FROM authors
1115
1116 OPEN authors_cursor
1117
1118 FETCH NEXT FROM authors_cursor
1119
1120 /*
1121 B. 使用嵌套游标生成报表输出
1122 下例显示如何嵌套游标以生成复杂的报表。为每个作者声明内部游标。
1123 */
1124
1125 SET NOCOUNT ON
1126
1127 DECLARE @au_id varchar(11), @au_fname varchar(20), @au_lname varchar(40),
1128 @message varchar(80), @title varchar(80)
1129
1130 PRINT "-------- Utah Authors report --------"
1131
1132 DECLARE authors_cursor CURSOR
1133 FOR
1134 SELECT au_id, au_fname, au_lname
1135 FROM authors
1136 WHERE state = "UT"
1137 ORDER BY au_id
1138
1139 OPEN authors_cursor
1140
1141 FETCH NEXT FROM authors_cursor
1142 INTO @au_id, @au_fname, @au_lname
1143
1144 WHILE @@FETCH_STATUS = 0
1145 BEGIN
1146 PRINT " "
1147 SELECT @message = "----- Books by Author: " +
1148 @au_fname + " " + @au_lname
1149
1150 PRINT @message
1151
1152 -- Declare an inner cursor based
1153 -- on au_id from the outer cursor.
1154
1155 DECLARE titles_cursor CURSOR FOR
1156 SELECT t.title
1157 FROM titleauthor ta, titles t
1158 WHERE ta.title_id = t.title_id AND
1159 ta.au_id = @au_id -- Variable value from the outer cursor
1160
1161 OPEN titles_cursor
1162 FETCH NEXT FROM titles_cursor INTO @title
1163
1164 IF @@FETCH_STATUS <> 0
1165 PRINT " <<No Books>>"
1166
1167 WHILE @@FETCH_STATUS = 0
1168 BEGIN
1169
1170 SELECT @message = " " + @title
1171 PRINT @message
1172 FETCH NEXT FROM titles_cursor INTO @title
1173
1174 END
1175
1176 CLOSE titles_cursor
1177 DEALLOCATE titles_cursor
1178
1179 -- Get the next author.
1180 FETCH NEXT FROM authors_cursor
1181 INTO @au_id, @au_fname, @au_lname
1182 END
1183
1184 CLOSE authors_cursor
1185 DEALLOCATE authors_cursor
1186 GO
1187
1188 -------- Utah Authors report --------
1189
1190 ----- Books by Author: Anne Ringer
1191 The Gourmet Microwave
1192 Is Anger the Enemy?
1193
1194 ----- Books by Author: Albert Ringer
1195 Is Anger the Enemy?
1196 Life Without Fear
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207 (8)触发器
1208
1209
1210
1211
1212 -- 设定数据库的递归触发器
1213 alter database pubs
1214 set recursive_triggers on
1215 go
1216
1217 -- 创建数据表,并设定主键、外键以及缺省约束
1218 create table emp_mgr
1219 (
1220 Emp char(30) primary key,
1221 Mgr char(30) null foreign key references emp_mgr(Emp),
1222 NoOfReports int default 0
1223 )
1224 go
1225
1226 -- 创建插入触发器
1227 create trigger emp_marins
1228 on emp_mgr
1229 for insert
1230 as
1231 declare @e char(30),@m char(30)
1232 declare cur_mgr cursor for
1233 select emp_mgr.emp
1234 from emp_mgr,inserted
1235 where emp_mgr.emp = inserted.mgr
1236
1237 open cur_mgr
1238
1239 fetch next from cur_mgr into @e
1240
1241 while @@fetch_status = 0
1242 begin
1243 update emp_mgr
1244 set emp_mgr.NoOfReports = emp_mgr.NoOfReports + 1
1245 where emp_mgr.emp = @e
1246
1247 fetch next from cur_mgr into @e
1248 end
1249
1250 close cur_mgr
1251
1252 deallocate cur_mgr
1253
1254 go
1255
1256 -- 查看数据表相关触发器
1257 sp_helptrigger emp_mgr
1258 go
1259
1260
1261 create trigger emp_mgrupd
1262 on emp_mgr
1263 for update
1264 as
1265 if update (mgr)
1266 begin
1267 update emp_mgr
1268 set emp_mgr.NoOfReports = emp_mgr.NoofReports + 1
1269 from inserted
1270 where emp_mgr.emp = inserted.mgr
1271
1272 update emp_mgr
1273 set emp_mgr.NoOfReports = emp_mgr.NoOfReports -1
1274 from deleted
1275 where emp_mgr.emp = deleted.mgr
1276
1277 end
1278
1279 go
1280
1281
1282 insert emp_mgr(emp,mgr) values ('Harry',null)
1283 insert emp_mgr(emp,mgr) values ('Alice','Harry')
1284 insert emp_mgr(emp,mgr) values ('Paul','Alice')
1285 insert emp_mgr(emp,mgr) values ('Joe','Alice')
1286 insert emp_mgr(emp,mgr) values ('Dave','Joe')
1287 go
1288
1289 select * from emp_mgr
1290 go
1291
1292 update emp_mgr
1293 set mgr = 'Harry'
1294 where emp = 'Dave'
1295 go
1296
1297 select * from emp_mgr
1298 go
1299
1300
1301
1302 -- “进销存”系统(触发器的经典应用之一)
1303
1304 某“进销存”系统需要记录进货的信息以及出货的信息,并且当用户记录这些信息的同时,库存信息也需要进行相应的调整,
1305 比如:记录进货信息时,如果该货品是新货,在库存表中还不存在任何信息时,则需要添加一条库存信息(Insert),
1306 否则,只需要对相应的库存记录进行更新(Update);然而,在记录出货信息时,如果该货品在库存表中的库存量小于出货量时,
1307 则需抛出一个用户自定义的“应用错误”(raise_appliction_error),否则,只需要对相应的库存记录进行更新(Update)。
1308 那么,我们如何来作到数据库系统的自动完成。
1309
1310 create table 进货
1311 (
1312 货号 char(1) not null,
1313 数量 int not null,
1314 时间 smalldatetime
1315 )
1316
1317 create table 库存
1318 (
1319 货号 char(1) not null,
1320 数量 int not null
1321 )
1322
1323
1324 create table 出货
1325 (
1326 货号 char(1) not null,
1327 数量 int not null,
1328 时间 smalldatetime
1329 )
1330
1331 drop table 库存
1332 drop table 进货
1333 drop table 出货
1334
1335 select * from 进货
1336 select * from 库存
1337 select * from 出货
1338
1339
1340 create proc pro进货
1341 (
1342 @h char(1),
1343 @s int,
1344 @j smalldatetime
1345 )
1346 as
1347 insert into 进货 values (@h, @s, @j)
1348
1349 if exists(select * from 库存 where 货号 = @h)
1350 update 库存 set 数量 = 数量 + @s where 货号 = @h
1351 else
1352 insert into 库存 values (@h, @s)
1353 go
1354
1355 execute pro进货 'A', 120, '2005-12-28'
1356 execute pro进货 'A', 180, '2005-12-29'
1357
1358
1359 create proc pro出货
1360 (
1361 @h char(1),
1362 @s int,
1363 @j smalldatetime
1364 )
1365 as
1366 if exists(select * from 库存 where 货号 = @h)
1367 begin
1368 if exists(select 数量 from 库存 where 货号 = @h and 数量 >= @s)
1369 begin
1370 update 库存 set 数量 = 数量 - @s where 货号 = @h
1371 insert into 出货 values (@h, @s, @j)
1372 end
1373 else
1374 print 'No,you need too more!'
1375 end
1376 else
1377 print 'No, no you need Dongxi!'
1378 go
1379
1380 execute pro出货 'D', 120, '2005-12-28'
1381 execute pro出货 'A', 680, '2005-12-29'
1382 execute pro出货 'A', 80, '2005-12-29'
1383
1384 create proc pro进货
1385 (
1386 @h char(1),
1387 @s int,
1388 @j smalldatetime
1389 )
1390 as
1391 insert into 进货 values (@h, @s, @j)
1392 go
1393
1394 create trigger tri进货
1395 on 进货
1396 after insert
1397 as
1398 declare @h char(1)
1399 declare @s int
1400 select @h = 货号, @s = 数量 from inserted
1401
1402 if exists(select * from 库存 where 货号 = @h)
1403 update 库存 set 数量 = 数量 + @s where 货号 = @h
1404 else
1405 insert into 库存 values (@h, @s)
1406 go
1407
1408
1409
1410
1411 create proc pro销售
1412 (
1413 @h char(1),
1414 @s int,
1415 @j smalldatetime
1416 )
1417 as
1418 if exists(select * from 库存 where 货号 = @h)
1419 insert into 销售 values (@h, @s, @j)
1420 go
1421
1422
1423 create trigger tri销售
1424 on 销售
1425 after insert
1426 as
1427 if (select 数量 from inserted) > (select 数量 from 库存 where 货号 = (select 货号 from inserted))
1428 begin
1429 print 'Nononono!'
1430 rollback
1431 end
1432 else
1433 update 库存 set 数量 = 数量 - (select 数量 from inserted) where 货号 in (select 货号 from inserted)
1434 go
1435
1436
1437
1438
1439
1440
1441 -- 部门管理(触发器的递归实现的经典应用之一)
1442 use pubs
1443 go
1444
1445 drop table departments
1446 go
1447
1448 -- 定义数据表
1449 create table Departments
1450 (
1451 dep_id int not null identity(1,1) primary key,
1452 dep_name varchar(18) not null unique,
1453 dep_parent int not null,
1454 dep_description varchar(42) null
1455 )
1456 go
1457
1458 -- 添加基本数据
1459 insert into departments
1460 (dep_name, dep_parent, dep_description)
1461 values
1462 ('上海', 0, '省级代理')
1463 go
1464
1465 insert into departments
1466 (dep_name, dep_parent, dep_description)
1467 values
1468 ('北京', 0, '省级代理')
1469 go
1470
1471 insert into departments
1472 (dep_name, dep_parent, dep_description)
1473 values
1474 ('湖南', 0, '省级代理')
1475 go
1476
1477 insert into departments
1478 (dep_name, dep_parent, dep_description)
1479 values
1480 ('长沙', 3, '市级代理')
1481 go
1482
1483 insert into departments
1484 (dep_name, dep_parent, dep_description)
1485 values
1486 ('株洲', 3, '市级代理')
1487 go
1488
1489 insert into departments
1490 (dep_name, dep_parent,dep_description)
1491 values
1492 ('湘潭', 3, '市级代理')
1493 go
1494
1495 insert into departments
1496 (dep_name, dep_parent, dep_description)
1497 values
1498 ('石峰', 5, '区级代理')
1499 go
1500
1501 insert into departments
1502 (dep_name, dep_parent, dep_description)
1503 values
1504 ('天元', 5, '区级代理')
1505 go
1506
1507 insert into departments
1508 (dep_name, dep_parent,dep_description)
1509 values
1510 ('芦淞', 5, '区级代理')
1511 go
1512
1513 select * from departments
1514 go
1515
1516
1517 -- 定义添加部门的存储过程
1518 create procedure proc_InsertDepartment
1519 @dep_parent_id int,
1520 @dep_name varchar(20),
1521 @dep_id int output
1522 as
1523 insert into departments (dep_name, dep_parent,dep_description) values (@dep_name, @dep_parent_id, '代理')
1524 select @dep_id = @@IDENTITY
1525 go
1526
1527 -- 定义修改指定部门的名称的存储过程
1528 create procedure proc_UpdateDepartment
1529 @dep_id int,
1530 @dep_name varchar(20)
1531 as
1532 update departments set dep_name = @dep_name where dep_id = @dep_id
1533 go
1534
1535 -- 定义删除指定部门以及相应子部门的存储过程
1536 create procedure proc_DeleteDepartment
1537 @dep_id int
1538 as
1539 delete from departments where dep_id = @dep_id
1540 go
1541
1542 -- 定义删除触发器(递归)
1543 create trigger tri_del_dep
1544 on departments
1545 for delete
1546 as
1547 -- 获取被删除部门的编号
1548 -- 检查是否存在子部门
1549 if exists(select * from departments where dep_parent in (select dep_id from deleted ))
1550 begin
1551 -- 如果返回值为真,删除相应子部门,激活子部门的删除触发器,进行递归调用
1552 delete from departments where dep_parent in (select dep_id from deleted )
1553 end
1554 go
1555
1556 -- 启动直接递归触发器
1557 exec sp_dboption 'pubs','recursive triggers','true'
1558
1559 -- 启动间接递归触发器
1560 exec sp_configure 'nested triggers','1'
1561
1562
1563
1564 (9)链接服务
1565 -- 在SQL Server上创建一个链接服务:与其他数据库建立连接,将其数据表或是视图作为本地信息源访问
1566 -- 比如:将Access数据库Northwind作为一个链接服务源
1567 EXEC sp_addlinkedserver
1568 @server = 'SEATTLE Mktg',
1569 @provider = 'Microsoft.Jet.OLEDB.4.0',
1570 @srvproduct = 'OLE DB Provider for Jet',
1571 @datasrc = 'C:\Program Files\Microsoft Office\OFFICE11\SAMPLES\Northwind.mdb'
1572
1573
1574 SELECT *
1575 into #au4
1576 FROM OPENQUERY([SEATTLE Mktg], 'SELECT * FROM 产品')
1577 GO
1578
1579 select *
1580 from #au4