MSSQL之二十一 存储过程案例

举报
tea_year 发表于 2021/12/29 23:20:14 2021/12/29
【摘要】 Stored Procedure(存储过程)编写经验和优化措施  一、前言:在经过一段时间的存储过程开发之后,写下了一些开发时候的小结和经验与大家共享,希望对大家有益,主要是针对Sybase和SQL Server数据库,但其它数据库应该有一些共性。 二、适合读者对象:数据库开发程序员,数据库的数据量很多,涉及到对SP(存储...

  
  1. Stored Procedure(存储过程)编写经验和优化措施 
  2. 一、前言:在经过一段时间的存储过程开发之后,写下了一些开发时候的小结和经验与大家共享,希望对大家有益,主要是针对Sybase和SQL Server数据库,但其它数据库应该有一些共性。
  3. 二、适合读者对象:数据库开发程序员,数据库的数据量很多,涉及到对SP(存储过程)的优化的项目开发人员,对数据库有浓厚兴趣的人。
  4. 三、介绍:在数据库的开发过程中,经常会遇到复杂的业务逻辑和对数据库的操作,这个时候就会用SP来封装数据库操作。如果项目的SP较多,书写又没有一定的规范,将会影响以后的系统维护困难和大SP逻辑的难以理解,另外如果数据库的数据量大或者项目对SP的性能要求很,就会遇到优化的问题,否则速度有可能很慢,经过亲身经验,一个经过优化过的SP要比一个性能差的SP的效率甚至高几百倍。
  5. 四、内容:
  6. 1、开发人员如果用到其他库的TableView,务必在当前库中建立View来实现跨库操作,最好不要直接使用“databse.dbo.table_name”,因为sp_depends不能显示出该SP所使用的跨库tableview,不方便校验。
  7. 2、开发人员在提交SP前,必须已经使用set showplan on分析过查询计划,做过自身的查询优化检查。
  8. 3、高程序运行效率,优化应用程序,在SP编写过程中应该注意以下几点:
  9. a)        SQL的使用规范:
  10. i.  尽量避免大事务操作,慎用holdlock子句,提高系统并发能力。
  11. ii. 尽量避免反复访问同一张或几张表,尤其是数据量较大的表,可以考虑先根据条件提取数据到临时表中,然后再做连接。
  12. iii.尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该改写;如果使用了游标,就要尽量避免在游标循环中再进行表连接的操作。
  13. iv. 注意where字句写法,必须考虑语句顺序,应该根据索引顺序、范围大小来确定条件子句的前后顺序,尽可能的让字段顺序与索引顺序相一致,范围从大到小。
  14. v.  不要在where子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
  15. vi. 尽量使用exists代替select count(1)来判断是否存在记录,count函数只有在统计表中所有行数时使用,而且count(1)比count(*)更有效率。
  16. vii.尽量使用“>=”,不要使用“>”。
  17. viii.注意一些or子句和union子句之间的替换
  18. ix.注意表之间连接的数据类型,避免不同类型数据之间的连接。
  19. x. 注意存储过程中参数和数据类型的关系。
  20. xi.注意insertupdate操作的数据量,防止与其他应用冲突。如果数据量超过200个数据页面(400k),那么系统将会进行锁升级,页级锁会升级成表级锁。
  21. b) 索引的使用规范:
  22. i.  索引的创建要与应用结合考虑,建议大的OLTP表不要超过6个索引。
  23. ii. 尽可能的使用索引字段作为查询条件,尤其是聚簇索引,必要时可以通过index index_name来强制指定索引
  24. iii.避免对大表查询时进行table scan,必要时考虑新建索引。
  25. iv. 在使用索引字段作为条件时,如果该索引是联合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用。
  26. v.  要注意索引的维护,周期性重建索引,重新编译存储过程。
  27. c)tempdb的使用规范:
  28. i.  尽量避免使用distinctorder bygroup byhavingjoin、cumpute,因为这些语句会加重tempdb的负担。
  29. ii. 避免频繁创建和删除临时表,减少系统表资源的消耗。
  30. iii.在新建临时表时,如果一次性插入数据量很大,那么可以使用select into代替create table,避免log,提高速度;如果数据量不大,为了缓和系统表的资源,建议先create table,然后insert
  31. iv. 如果临时表的数据量较大,需要建立索引,那么应该将创建临时表和建立索引的过程放在单独一个子存储过程中,这样才能保证系统能够很好的使用到该临时表的索引。
  32. v.  如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先truncate table,然后drop table,这样可以避免系统表的较长时间锁定。
  33. vi. 慎用大的临时表与其他大表的连接查询和修改,减低系统表负担,因为这种操作会在一条语句中多次使用tempdb的系统表。
  34. d)合理的算法使用:
  35. 根据上面已提到的SQL优化技术和ASE Tuning手册中的SQL优化内容,结合实际应用,采用多种算法进行比较,以获得消耗资源最少、效率最高的方法。具体可用ASE调优命令:set statistics io on, set statistics time on , set showplan on 等。
  36. ===============================
  37. 金额阿拉伯数字转换为中文的自定义函数
  38. CREATE FUNCTION ChangeBigSmall
  39. (@ChangeMoney money)  
  40. RETURNS VarChar(100) AS   
  41. BEGIN 
  42.     Declare    @String1    char(20)
  43.     Declare    @String2    char(30)
  44.     Declare    @String4    Varchar(100)
  45.     Declare @String3     Varchar(100)    --从原A值中取出的值
  46.     Declare @i         int        --循环变量
  47.     Declare @J         Int        --A的值乘以100的字符串长度
  48.     Declare @Ch1         Varchar(100)    --数字的汉语读法
  49.     Declare @Ch2         Varchar(100)    --数字位的汉字读法
  50.     Declare @Zero         Int        --用来计算连续有几个零
  51.     Declare    @Returnvalue    VarChar(100)
  52.     Select  @Returnvalue = ''
  53.     Select     @String1 = '零壹贰叁肆伍陆柒捌玖'
  54.     Select    @String2 = '万仟佰拾亿仟佰拾万仟佰拾元角分'
  55.     Select @String4 = Cast(@ChangeMoney*100 as int)   
  56.     select @J=len(cast((@ChangeMoney*100) as int))
  57.     Select @String2=Right(@String2,@J)
  58.     Select    @i = 1 
  59.     while    @i<= @j Begin
  60.         Select @String3 = Substring(@String4,@i,1)
  61.         if @String3<>'0' Begin
  62.             Select     @Ch1 = Substring(@String1, Cast(@String3 as Int) + 1, 1)
  63.             Select    @Ch2 = Substring(@String2, @i, 1)
  64.             Select    @Zero = 0                    --表示本位不为零
  65.         end
  66.         else Begin
  67.             If (@Zero = 0) Or (@i = @J - 9) Or (@i = @J - 5) Or (@i = @J - 1)
  68.                         Select @Ch1 = '零' 
  69.                     Else
  70.                         Select @Ch1 = ''
  71.                     Select @Zero = @Zero + 1             --表示本位为0
  72.                         
  73.             --如果转换的数值需要扩大,那么需改动以下表达式 I 的值。
  74.             Select @Ch2 = ''
  75.                 If @i = @J - 10  Begin
  76.                         Select @Ch2 = '亿'
  77.                         Select @Zero = 0
  78.             end
  79.                     
  80.             If @i = @J - 6 Begin
  81.                         Select @Ch2 = '万'
  82.                         Select @Zero = 0
  83.             end
  84.                     
  85.             if @i = @J - 2 Begin
  86.                         Select @Ch2 = '元'
  87.                         Select @Zero = 0
  88.             end
  89.                     
  90.             If @i = @J 
  91.                         Select @Ch2 = '整'
  92.                        
  93.         end
  94.         Select @Returnvalue = @Returnvalue + @Ch1 + @Ch2
  95.         select @i = @i+1
  96.     end
  97.     --最后将多余的零去掉
  98.     If CharIndex('仟仟',@Returnvalue) <> 0 
  99.             Select @Returnvalue = Replace(@Returnvalue, '仟仟', '仟')
  100.     If CharIndex('佰佰',@Returnvalue) <> 0 
  101.             Select @Returnvalue = Replace(@Returnvalue, '佰佰', '佰')
  102.         If CharIndex('零元',@Returnvalue) <> 0 
  103.             Select @Returnvalue = Replace(@Returnvalue, '零元', '元')
  104.     
  105.         If CharIndex('零万',@Returnvalue) <> 0 
  106.             Select @Returnvalue = Replace(@Returnvalue, '零万', '万')
  107.    
  108.         If CharIndex('零亿',@Returnvalue) <> 0
  109.             Select @Returnvalue = Replace(@Returnvalue, '零亿', '亿')
  110.     
  111.         If CharIndex('零整',@Returnvalue) <> 0 
  112.             Select @Returnvalue = Replace(@Returnvalue, '零整', '整')
  113.     
  114.     If CharIndex('零佰',@Returnvalue) <> 0 
  115.             Select @Returnvalue = Replace(@Returnvalue, '零佰', '零')
  116.     If CharIndex('零仟',@Returnvalue) <> 0 
  117.             Select @Returnvalue = Replace(@Returnvalue, '零仟', '零')
  118.     If CharIndex('元元',@Returnvalue) <> 0 
  119.             Select @Returnvalue = Replace(@Returnvalue, '元元', '元')
  120.     return @Returnvalue
  121. END
  122. ===========================================
  123. MS SQL SERVER 图像或大文本的输入输出
  124. 在MS SQL SERVER 安装目录下有个可执行文件叫 TEXTCOPY.EXE 
  125. 可对 MS SQL SERVER 中的文本或图像数据进行输入输出. 
  126. 不过你可以在MS-DOS方式下执行textcopy /? 得到它的描述。 
  127. 下面是这个工具的描述: 
  128. Copies a single text or image value into or out of SQL Server. The val
  129. ue 
  130. is a specified text or image 'column' of a single row (specified by th
  131. "where clause") of the specified 'table'.  
  132. If the direction is IN (/I) then the data from the specified 'file' is
  133. copied into SQL Server, replacing the existing text or image value. If
  134. the 
  135. direction is OUT (/O) then the text or image value is copied from 
  136. SQL Server into the specified 'file', replacing any existing file. 
  137. TEXTCOPY [/S ][sqlserver]] [/U [login]] [/P ][password]] 
  138.   [/D ][database]] [/T table] [/C column] [/W"where clause"] 
  139.   [/F file] [{/I | /O}] [/K chunksize] [/Z] [/?] 
  140.   /S sqlserver       The SQL Server to connect to. If 'sqlserver' is n
  141. ot 
  142.                      specified, the local SQL Server is used. 
  143.   /U login           The login to connect with. If 'login' is not spec
  144. ified, 
  145.                      a trusted connection will be used. 
  146.   /P password        The password for 'login'. If 'password' is not 
  147.                      specified, a NULL password will be used. 
  148.   /D database        The database that contains the table with the tex
  149. t or 
  150.                      image data. If 'database' is not specified, the d
  151. efault 
  152.                      database of 'login' is used. 
  153.   /T table           The table that contains the text or image value. 
  154.   /C column          The text or image column of 'table'
  155.   /W "where clause"  A complete where clause (including the WHERE keyw
  156. ord) 
  157.                      that specifies a single row of 'table'
  158.   /F file            The file name. 
  159.   /I                 Copy text or image value into SQL Server from 'fi
  160. le'
  161.   /O                 Copy text or image value out of SQL Server into '
  162. file'
  163.   /K chunksize       Size of the data transfer buffer in bytes. Minimu
  164.                      value is 1024 bytes, default value is 4096 bytes.
  165.   /Z                 Display debug information while running. 
  166.   /?                 Display this usage information and exit. 
  167. You will be prompted for any required options you did not specify. 
  168. 为此, 可写一个存储过程,调用这个命令 
  169. CREATE PROCEDURE sp_textcopy ( 
  170.   @srvname     varchar (30), 
  171.   @login       varchar (30), 
  172.   @password    varchar (30), 
  173.   @dbname      varchar (30), 
  174.   @tbname      varchar (30), 
  175.   @colname     varchar (30), 
  176.   @filename    varchar (30), 
  177.   @whereclause varchar (40), 
  178.   @direction   char(1)) 
  179. AS 
  180. DECLARE @exec_str varchar (255
  181. SELECT @exec_str = 
  182.          'textcopy /S ' + @srvname + 
  183.          ' /U ' + @login + 
  184.          ' /P ' + @password + 
  185.          ' /D ' + @dbname + 
  186.          ' /T ' + @tbname + 
  187.          ' /C ' + @colname + 
  188.          ' /W "' + @whereclause + 
  189.          '" /F ' + @filename + 
  190.          ' /' + @direction 
  191. EXEC master..xp_cmdshell @exec_str 
  192. 下面是一个拷贝图像到SQL Server的pubs数据库的例子, 表名pub_info, 字段名
  193. logo,图像文件名picture.bmp,保存到pub_id='0736'记录 sp_textcopy @srvn
  194. ame = 'ServerName'
  195.             @login = 'Login'
  196.             @password = 'Password'
  197.             @dbname = 'pubs'
  198.             @tbname = 'pub_info'
  199.             @colname = 'logo'
  200.             @filename = 'c:\picture.bmp'
  201.             @whereclause = " WHERE pub_id='0736' ", 
  202.             @direction = 'I'

  
  1. select 联系人,订购日期,订购数量,产品名称
  2. from 客户信息表 a,订单信息表 b,产品信息表 c
  3. where a.客户编号=b.客户编号 and b.产品编号=c.产品编号
  4. select 联系人,订购日期,订购数量,产品名称
  5. from 客户信息表 a inner join 订单信息表 b
  6. on a.客户编号=b.客户编号 inner join 产品信息表 c
  7. on b.产品编号=c.产品编号
  8. ---------------------------------------------
  9. use 范例
  10. go
  11. --创建存储过程
  12. create procedure Query
  13. as
  14. select 联系人,订购日期,订购数量,产品名称
  15. from 客户信息表 a,订单信息表 b,产品信息表 c
  16. where a.客户编号=b.客户编号 and b.产品编号=c.产品编号
  17. --执行存储过程 sp_recompile作用:对自己定义的存储过程进行重新编译
  18. exec sp_recompile Query
  19. exec Query
  20. --删除存储过程
  21. drop procedure Query
  22. select * from master.dbo.syscomments
  23. --查看存储过程源代码
  24. exec sp_helptext sp_renamedb
  25. --修改存储过程
  26. alter procedure Query
  27. with encryption
  28. as
  29. select 联系人,订购日期,订购数量,产品名称
  30. from 客户信息表 a,订单信息表 b,产品信息表 c
  31. where a.客户编号=b.客户编号 and b.产品编号=c.产品编号
  32. --====================================================================
  33. -- 输出参数
  34. create proc QueryName
  35. @ProductID char(10), --输入参数
  36. @ProductName char(10) output -- 输出参数
  37. as
  38. select @ProductName=产品名称 from 产品信息表
  39. where 产品编号 = @ProductID
  40. --return @ProductName
  41. go
  42. select * from 产品信息表
  43. --执行
  44. -- declare @prodName varchar(25)
  45. -- exec QueryName 'P003',@ProductName=@prodName OUTPUT
  46. --
  47. -- print @prodName
  48. declare @prodName varchar(25)
  49. exec QueryName 'P003' ,@prodName output
  50. print @prodName
  51. --=====================================
  52. create proc abc
  53. as
  54. begin tran
  55. print 'fs'
  56. if @@error > 0 --or @@rowcount <> 1
  57. goto seed
  58. print 'fs'
  59. seed:
  60. if @@error > 0 --or @@rowcount <> 1
  61. begin
  62. --select @@error
  63. --select @@rowcount as ssss
  64. rollback tran
  65. print '发生错误提交无法完成!!!!'
  66. end
  67. else
  68. begin
  69. commit tran
  70. print '无错误发生提交正常!!!'
  71. end
  72. go
  73. --==============================================================
  74. exec abc
  75. drop proc abc

 

 


  
  1. /*
  2. 存储过程:
  3. 将常用的或很复杂的工作,预先以sql程序写好,
  4. 然后指定一个程序名称保存起来,那么以后只要使用execute指令
  5. 来执行这个程序,即可自动完成该项工作。
  6. 优点:
  7. 1.存储过程是预先编译的,执行效率高。
  8. 2.存储过程的执行是在服务器端,这样就可极大地降低网络流量。
  9. 3.重复使用。
  10. 4.如果所有客户端都通过存储过程来进行访问数据,这
  11. 样可禁止对物理表的直接访问,提高数据安全性。
  12. 存储过程的种类:
  13. 1.系统存储过程。 以sp_开头
  14. 2.扩展存储过程。 以xp_开头
  15. 3.用户定义存储过程。
  16. */
  17. use master
  18. exec xp_cmdshell 'dir C:'
  19. -------------------------------------------------------------------------------------------------------------------------------
  20. create table 标标公司
  21. (
  22. 产品名称 varchar(50) not null,
  23. 价格 smallmoney not null
  24. )
  25. create table 旗旗公司
  26. (
  27. 产品名称 varchar(50) not null,
  28. 价格 smallmoney not null
  29. )
  30. insert 标标公司 (产品名称,价格) values ('原子笔',10)
  31. insert 标标公司 (产品名称,价格) values ('钢笔',90)
  32. insert 标标公司 (产品名称,价格) values ('荧光笔',40)
  33. insert 标标公司 (产品名称,价格) values ('水彩笔',60)
  34. insert 旗旗公司 (产品名称,价格) values ('原子笔',10)
  35. insert 旗旗公司 (产品名称,价格) values ('钢笔',100)
  36. insert 旗旗公司 (产品名称,价格) values ('2B铅笔',20)
  37. insert 旗旗公司 (产品名称,价格) values ('毛铅笔',50)
  38. select * from 标标公司
  39. select * from 旗旗公司
  40. truncate table 标标公司
  41. -----------------------------------------建立存储过程----------------------------------------------------
  42. alter procedure myproc1
  43. with encryption --encryption对存储过程进行加密
  44. as
  45. if 1<2
  46. print 'AAAAA'
  47. select * from 标标公司
  48. where 价格 > 15
  49. go
  50. ------------------
  51. exec myproc1
  52. -----------------------------------------建立视图--------------------------------------------------------
  53. alter view myview1
  54. with encryption
  55. as
  56. select * from 标标公司
  57. where 价格 > 15
  58. go
  59. ---------------------------
  60. select * from myview1
  61. ------------------------建立存储过程并设置参数------------------------------
  62. create procedure myproc2
  63. @param1 char(10)=null,
  64. @param2 money=NULL
  65. --with encryption
  66. as
  67. insert 标标公司 (产品名称,价格) values (@param1,@param2)
  68. go
  69. --================================================================
  70. exec myproc2 '铅笔盒',120    -- 执行存储过程,并给定参数
  71. go
  72. --=============================================================
  73. drop procedure myproc2 -- 删除存储过程
  74. select * from 标标公司
  75. -------------------------------------------
  76. -------------------------------------------
  77. create proc myproc3
  78. @param1 char(10) =null,
  79. @param2 money = null,
  80. @param3 money output
  81. as
  82. insert 标标公司 (产品名称,价格) values (@param1,@param2)
  83. select @param3 = sum(价格)
  84. from 标标公司
  85. where 价格 > 15
  86. go
  87. -------------------------------------------------------
  88. ------------------------------------
  89. -- 执行myproc3存储过程,并将返回值指定给@sum.
  90. declare @sum money
  91. exec myproc3 '金笔',1200,@sum output
  92. print '目前的总价格为: ' + convert(varchar,@sum)
  93. select * from 标标公司
  94. -------------------------------------
  95. -------------------------------------建立群组存储过程-------------------------
  96. create proc myproc5;1
  97. as
  98. select * from 旗旗公司
  99. go
  100. create proc myproc5;2
  101. as
  102. select * from 标标公司
  103. go
  104. exec myproc5;1
  105. exec myproc5;2
  106. drop proc myproc5
  107. --------------------------------------------修改存储过程-------------------------------------------------
  108. alter procedure myproc2
  109. @param1 char(10),
  110. @param2 money
  111. with encryption
  112. as
  113. insert 标标公司 (产品名称,价格) values (@param1,@param2)
  114. go
  115. -----------------------------------------------------------------------------------------------------

 


  
  1. drop proc myproc
  2. create proc myproc
  3. as
  4. declare @v int
  5. select @v=5
  6. while @v>0
  7. begin
  8. select @v*@v
  9. select @v=@v-1
  10. if @v=2
  11. begin
  12. raiserror('计数器已小于3',16,5)
  13. --break
  14. return
  15. end
  16. end
  17. print 'wwwwwwwwwwwwwwwww'
  18. exec myproc

  
  1. 这个存储过程执行的速度还不错.500W速度分页只要2秒,任何页数
  2. 可是有点问题就是,如果排序不是主键,ID,那么分页就会出错,不知道各位有什么好个意见,修改一下
  3. -------------------------------------------------------
  4. create procedure SqlDataPaging
  5. @tbName varchar(255), --表名
  6. @tbFields varchar(1000), --返回字段
  7. @OrderField varchar(255), --排序的字段名
  8. @PageSize int, --页尺寸
  9. @PageIndex int, --页码
  10. @OrderType bit, --排序类型,1是升序,0是降序
  11. @strWhere varchar(1500), --查询条件
  12. @Total int output --返回总记录数
  13. as
  14. declare @strSql varchar(5000) --主语句
  15. declare @strOrder varchar(200) --排序
  16. declare @strSqlCount nvarchar(500)--查询记录总数主语句
  17. declare @strtemp varchar(50) --排序附加语句
  18. --------------排序-----------------1是降序,0未升序
  19. if @OrderType !=0
  20. begin
  21. set @strtemp= '>(select max('
  22. set @strOrder='order by ' + @OrderField + ' asc '
  23. end
  24. else
  25. begin
  26. set @strtemp= '<(select min('
  27. set @strOrder='order by '+ @OrderField + ' desc'
  28. end
  29. --------------总记录数---------------
  30. if @strWhere !=''
  31. begin
  32. set @strSqlCount='Select @TotalCout=count(*) from ' + @tbName + 'where '+ @strWhere
  33. end
  34. else
  35. begin
  36. set @strSqlCount='Select @TotalCout=count(*) from ' + @tbName
  37. end
  38. --------------如果是第一页------------
  39. if @PageIndex =1
  40. begin
  41. if @strWhere !=''
  42. begin
  43. set @strSql = 'Select top' +str(@PageSize)+ ' ' + @tbFields + ' from '+ @tbName +' where ' + @strWhere + ' ' + @strOrder
  44. end
  45. else
  46. begin
  47. set @strSql = 'Select top' +str(@PageSize)+ ' ' + @tbFields + ' from '+ @tbName + ' ' + @strOrder
  48. end
  49. end
  50. else
  51. begin
  52. if @strWhere !=''
  53. begin
  54. set @strSql='Select top ' +str(@PageSize) + ' ' + @tbFields
  55. +' from ' + @tbName + ' where '+@OrderField +' '
  56. + @strtemp+ ' ' +@OrderField+ ') from (select top'
  57. +str((@PageIndex-1)*@PageSize) + ' '+@OrderField +' from '+@tbName
  58. + @strWhere+ ' '+ @strOrder +') as tb)'+ @strOrder
  59. end
  60. else
  61. begin
  62. set @strSql='Select top ' + str(@PageSize) + ' ' + @tbFields
  63. +' from ' + @tbName + ' where '+@OrderField + ' '
  64. + @strtemp+ ' ' +@OrderField+ ') from (select top'
  65. +str((@PageIndex-1)*@PageSize) + ' '+@OrderField +' from '+@tbName
  66. + ' '+ @strOrder +') as tb)'+ @strOrder
  67. end
  68. end
  69. exec sp_executesql @strSqlCount,N'@TotalCout int output',@Total output
  70. exec(@strSql)
  71. -----------------------------------
  72. CREATE PROC sp_PageView
  73. @tbname sysname, --要分页显示的表名
  74. @FieldKey nvarchar(1000), --用于定位记录的主键(惟一键)字段,可以是逗号分隔的多个字段
  75. @PageCurrent int=1, --要显示的页码
  76. @PageSize int=10, --每页的大小(记录数)
  77. @FieldShow nvarchar(1000)='', --以逗号分隔的要显示的字段列表,如果不指定,则显示所有字段
  78. @FieldOrder nvarchar(1000)='', --以逗号分隔的排序字段列表,可以指定在字段后面指定DESC/ASC用于指定排序顺序
  79. @Where nvarchar(1000)='', --查询条件
  80. @PageCount int OUTPUT --总页数
  81. AS
  82. SET NOCOUNT ON
  83. --检查对象是否有效
  84. IF OBJECT_ID(@tbname) IS NULL
  85. BEGIN
  86. RAISERROR(N'对象"%s"不存在',1,16,@tbname)
  87. RETURN
  88. END
  89. IF OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsTable')=0
  90. AND OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsView')=0
  91. AND OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsTableFunction')=0
  92. BEGIN
  93. RAISERROR(N'"%s"不是表、视图或者表值函数',1,16,@tbname)
  94. RETURN
  95. END
  96. --分页字段检查
  97. IF ISNULL(@FieldKey,N'')=''
  98. BEGIN
  99. RAISERROR(N'分页处理需要主键(或者惟一键)',1,16)
  100. RETURN
  101. END
  102. --其他参数检查及规范
  103. IF ISNULL(@PageCurrent,0)<1 SET @PageCurrent=1
  104. IF ISNULL(@PageSize,0)<1 SET @PageSize=10
  105. IF ISNULL(@FieldShow,N'')=N'' SET @FieldShow=N'*'
  106. IF ISNULL(@FieldOrder,N'')=N''
  107. SET @FieldOrder=N''
  108. ELSE
  109. SET @FieldOrder=N'ORDER BY '+LTRIM(@FieldOrder)
  110. IF ISNULL(@Where,N'')=N''
  111. SET @Where=N''
  112. ELSE
  113. SET @Where=N'WHERE ('+@Where+N')'
  114. --如果@PageCount为NULL值,则计算总页数(这样设计可以只在第一次计算总页数,以后调用时,把总页数传回给存储过程,避免再次计算总页数,对于不想计算总页数的处理而言,可以给@PageCount赋值)
  115. IF @PageCount IS NULL
  116. BEGIN
  117. DECLARE @sql nvarchar(4000)
  118. SET @sql=N'SELECT @PageCount=COUNT(*)'
  119. +N' FROM '+@tbname
  120. +N' '+@Where
  121. EXEC sp_executesql @sql,N'@PageCount int OUTPUT',@PageCount OUTPUT
  122. SET @PageCount=(@PageCount+@PageSize-1)/@PageSize
  123. END
  124. --计算分页显示的TOPN值
  125. DECLARE @TopN varchar(20),@TopN1 varchar(20)
  126. SELECT @TopN=@PageSize,
  127. @TopN1=@PageCurrent*@PageSize
  128. --第一页直接显示
  129. IF @PageCurrent=1
  130. EXEC(N'SELECT TOP '+@TopN
  131. +N' '+@FieldShow
  132. +N' FROM '+@tbname
  133. +N' '+@Where
  134. +N' '+@FieldOrder)
  135. ELSE
  136. BEGIN
  137. --生成主键(惟一键)处理条件
  138. DECLARE @Where1 nvarchar(4000),@s nvarchar(1000)
  139. SELECT @Where1=N'',@s=@FieldKey
  140. WHILE CHARINDEX(N',',@s)>0
  141. SELECT @s=STUFF(@s,1,CHARINDEX(N',',@s),N''),
  142. @Where1=@Where1
  143. +N' AND a.'+LEFT(@s,CHARINDEX(N',',@s)-1)
  144. +N'='+LEFT(@s,CHARINDEX(N',',@s)-1)
  145. SELECT @Where1=STUFF(@Where1+N' AND a.'+@s+N'='+@s,1,5,N''),
  146. @TopN=@TopN1-@PageSize
  147. --执行查询
  148. EXEC(N'SET ROWCOUNT '+@TopN1
  149. +N' SELECT '+@FieldKey
  150. +N' INTO # FROM '+@tbname
  151. +N' '+@Where
  152. +N' '+@FieldOrder
  153. +N' SET ROWCOUNT '+@TopN
  154. +N' DELETE FROM #'
  155. +N' SELECT '+@FieldShow
  156. +N' FROM '+@tbname
  157. +N' a WHERE EXISTS(SELECT * FROM # WHERE '+@Where1
  158. +N') '+@FieldOrder)
  159. END
  160. -------------------------------------------
  161. /*函数名称: GetRecordFromPage
  162. 函数功能: 获取指定页的数据
  163. 参数说明: @tblName 包含数据的表名
  164. @fldName 关键字段名
  165. @PageSize 每页记录数
  166. @PageIndex 要获取的页码
  167. @OrderType 排序类型, 0 - 升序, 1 - 降序
  168. @strWhere 查询条件(注意: 不要加where)
  169. 创建时间: 2004-07-04
  170. 修改时间: 2008-02-13
  171. */
  172. Alter PROCEDURE [dbo].[GetRecordFromPage]
  173. @tblName varchar(255), -- 表名
  174. @fldName varchar(255), -- 字段名
  175. @PageSize int = 10, -- 页尺寸
  176. @PageIndex int = 1, -- 页码
  177. @OrderType bit = 0, -- 设置排序类型, 非0 值则降序
  178. @IsCount bit = 0, -- 返回记录总数, 非0 值则返回
  179. @strWhere varchar(2000) = '' -- 查询条件(注意: 不要加where)
  180. AS
  181. declare @strSQL varchar(6000) -- 主语句
  182. declare @strTmp varchar(1000) -- 临时变量
  183. declare @strOrder varchar(500) -- 排序类型
  184. if @OrderType != 0
  185. begin
  186. set @strTmp = '<(select min'
  187. set @strOrder = ' order by [' + @fldName + '] desc'
  188. end
  189. else
  190. begin
  191. set @strTmp = '>(select max'
  192. set @strOrder = ' order by [' + @fldName +'] asc'
  193. end
  194. set @strSQL = 'select top ' + str(@PageSize) + ' * from ['
  195. + @tblName + '] where [' + @fldName + ']' + @strTmp + '(['
  196. + @fldName + ']) from (select top ' + str((@PageIndex-1)*@PageSize) + ' ['
  197. + @fldName + '] from [' + @tblName + ']' + @strOrder + ') as tblTmp)'
  198. + @strOrder
  199. if @strWhere != ''
  200. set @strSQL = 'select top ' + str(@PageSize) + ' * from ['
  201. + @tblName + '] where [' + @fldName + ']' + @strTmp + '(['
  202. + @fldName + ']) from (select top ' + str((@PageIndex-1)*@PageSize) + ' ['
  203. + @fldName + '] from [' + @tblName + '] where ' + @strWhere + ' '
  204. + @strOrder + ') as tblTmp) and ' + @strWhere + ' ' + @strOrder
  205. if @PageIndex = 1
  206. begin
  207. set @strTmp = ''
  208. if @strWhere != ''
  209. set @strTmp = ' where (' + @strWhere + ')'
  210. set @strSQL = 'select top ' + str(@PageSize) + ' * from ['
  211. + @tblName + ']' + @strTmp + ' ' + @strOrder
  212. end
  213. if @IsCount != 0
  214. set @strSQL = 'select count(' + @fldName + ') as Total from [' + @tblName + ']'
  215. exec (@strSQL)
  216. go
  217. -----------------------------

 

 

 

 

 

 

 

文章来源: aaaedu.blog.csdn.net,作者:tea_year,版权归原作者所有,如需转载,请联系作者。

原文链接:aaaedu.blog.csdn.net/article/details/52446787

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。