SQL Server 2005 存储过程

(《SQL Server 2005 编程入门经典》 第12章)

存储过程(stored procedure)有时也称为sproc。存储过程存储于数据库中而不是在单独的文件中,有输入参数、输出参数以及返回值等。

12.1 创建存储过程:基本语法

在数据库中,创建存储过程和创建其他对象的过程一样,除了它使用的AS关键字外。存储过程的基本语法如下:

CREATE PROCDUER|PROC 
    [[schema.][VARYING][=][OUT [PUT]][,
    [[schema.][VARYING][=][OUT [PUT]][,
    ...]]
[WITH
    RECOMPILE|ENCRYPTION|[EXECUTE AS {CALLER|SELF|OWNER|<'user name'>}]
[FOR REPLICATION]
AS
    |EXTERNAL NAME .

基础存储过程的示例

创建存储过程的代码如下:

USE Northwind
GO
CRREATE PROC spShippers
AS
    SELECT * FROM Shippers

执行存储过程:

EXEC spShippers

12.2 使用ALTER改变存储过程

当使用T-SQL编辑存储过程的时候,需要记住的是它完全取代了现存的存储过程。使用ALTER PROC和CREATE PROC的区别在于:

  • ALTER PROC期望找到现存的存储过程,而CREATE则不是。
  • ALTER PROC保留了已经建立的存储过程的任何权限。它在系统对象中保留了相同的对象ID并允许保留依赖关系。
  • ALTER PROC在其他对象上保留了任何依赖关系的信息,这些对象可以调用修改的存储过程。

注意:

如果执行DROP,然后使用CREATE,这和使用ALTER PROC语句一样,几乎都能得到相同的效果,除了一个很重要的区别——如果使用DROP和CREATE,则需要完全重新建立权限,权限规定了可以使用以及不能使用存储过程的用户。

12.3 删除存储过程

这个过程非常简单:

DROP PROC|PROCEDURE 

12.4 参数化(Parameterization)

声明参数

声明参数需要以下2到4部分信息:

  • 名称
  • 数据类型
  • 默认值
  • 方向

语法如下:

@parameter_name [AS] datatype[= default|NULL] [VARYING] [OUTPUT|OUT]

名称有一个简单的规则集合。首先,它必须以@开始。此外,命名规则除了不能有嵌套的空格外,它和SQL的命令规则是相同的。

数据类型可以使用SQL Server内置的或用户自定义的类型。

注意:

  • 声明CURSOR类型参数的时候,必须也使用VARYING和OUTPUT选项。
  • OUTPUT可以简写为OUT。

示例:

USE Northwind
GO
CREATE PROC spInsertShipper
    @CompanyName NVARCHAR(40),
    @Phone NVARCHAR(24)
AS
    INSERT INTO Shippers
    VALUES
        (@CompanyName, @Phone)

可以使用这个新的存储过程来插入新的数据:

EXEC spInstertShipper 'Speedy Shippers, Inc.', '(503)555-5566'

因为并没有为任何参数提供默认值,所以需要提供两个参数。这意味着为了成功运行该存储工程,则必须提供两个参数。

1. 提供默认值

为了使参数是可选的,可以提供默认值。示例:

USE Northwind
GO
CREATE PROC spInsertShipperOptionalPhone
    @CompanyName NVARCHAR(40),
    @Phone NVARCHAR(24) = NULL
AS
    INSERT INTO Shippers
    VALUES (@CompanyName, @Phone)

重新发出命令,但是使用新的存储过程:

EXEC spInsertShipperOptionalPhone 'Speedy Shippers, Inc'

这次一切顺利,成功插入了新的纪录。

2. 创建输出参数

示例:

USE Northwind
GO

CREATE PROC spInsertOrder
    @CustomerID NVARCHAR(5),
    @EmployeeID INT,
    @OrderDate DATETIME = NULL,
    @RequiredDate DATETIME = NULL,
    @ShippedDate DATETIME = NULL,
    @ShipVia INT,
    @Freight MONEY,
    @ShipName NVARCHAR(40) = NULL,
    @ShipAddress NVARCHAR(60) = NULL,
    @ShipCity NVARCHAR(15) = NULL,
    @ShipRegion NVARCHAR(15) = NULL,
    @ShipPostalCode NVARCHAR(10) = NULL,
    @ShipCountry NVARCHAR(15) = NULL,
    @OrderID INT OUTPUT
AS
    INSERT INTO Orders
    VALUES
    (
        @CustomerID,
        @EmployeeID,
        @OrderDate,
        @RequiredDate,
        @ShippedDate,
        @ShipVia,
        @Freight,
        @ShipName,
        @ShipAddress,
        @ShipCity,
        @ShipRegion,
        @ShipPostalCode,
        @ShipCountry
    )
SELECT @OrderID = @@IDENTITY

执行该存储过程的代码如下:

USE Northwind
GO

DECLARE @MyIdent INT
EXEC spInsertOrder
    @CustomerID = 'ALFKI',
    @EmployeeID = 5,
    @OrderDate = '5/1/1999'
    @ShipVia = 3,
    @Freight = 5.00,
    @OrderID = @MyIdenty OUTPUT

SELECT @MyIdent AS IdentityValue
SELECT OrderID, CustomerID, EmployeeID, OrderDate, ShipName
FROM Orders
WHERE OrderID = @MyIdent

需要注意以下几点:

  • 在存储过程声明中,输出参数需要使用OUTPUT关键字。
  • 调用存储过程的时候也必须使用OUTPUT关键字,才能保证参数被正确的输出。注意如果没有使用OUTPUT关键字,不会产生任何错误,但是此时输出参数的值将是无法保证的。
  • 赋给输出变量的变量不需要和存储过程中的内部参数拥有相同的名称。例如在本例中,内部参数叫做@OrderID,而传给值的变量叫做@MyIdent。
  • 需要使用EXEC(或EXECUTE)关键字来调用存储过程。

12.5 流控制语句

T-SQL提供了大多数流控制语句的典型的选择,包括:

  • IF...ELSE
  • GOTO
  • WHILE
  • WAITFOR
  • TRY/CATCH

同样也有CASE语句,但是它没有像其他语言中预期的那种流控制级的能力。

12.5.1 IF...ELSE语句

IF...ELSE语句的实现方式和C是接近相同的。基本的语法如下:

IF 
     | BEGIN  END
[ELSE
     | BEGIN  END]

其中的表达式可以是取布尔值的任意表达式。

提示:

不恰当的使用NULL值是个常见的陷阱。例如经常会有如下错误出现:

IF @MyVar = NULL

在大多数系统上(遵循ANSI标准)这样的表达式永远都不会为真,并且为绕过所有的NULL值结束。想要判断一个值是否为空应该这样来写:

IF @MyVar IS NULL

不要忘记了NULL不等于任何值——甚至是NULL。不要使用"="而要使用"IS"。

 

DATEDIFF函数

DATEDIFF的语法如下:

DATEDIFF (, , )

DATEDIFF可以比较日期型数据的任意部分,可以从年到毫秒。start date和end date参数是合法的日期表达式。datepart参数可以是下列的值:

datepart

缩写

year, yy, yyyy

季度

quarter,qq, q

month, mm, m

星期

week, dw, w

day, dd, d

hour, hh

minute, mi, n

second, ss, s

毫秒

millisecond, ms

1. ELSE子句

注意:

结果返回值为NULL的表达式会被当作FALSE从而进入ELSE子句。也就是说,如果IF子句中的语句返回值为FALSE或者NULL,则执行ELSE子句中的语句。

 

2. 从DATETIME字段中截取时间

为了能截取日期信息,要么把日期分成多个部分,然后不带时间地进行重组,要么可以使用CONVERT函数,该函数能把它转换为不带时间的日期,并且也能把它转换回来。

CONVERT()原来是SQL Server中唯一一个用来在数据类型之间转换数据的方法。现在,CAST()复制了它的大部分功能,并且是兼容ANSI的。然而,CONVERT()还是有一些特殊的日期格式化处理的能力,这些是CAST所不具备的。

CONVERT的语法如下:

CONVERT (, ,