将 SQL 过程重写为 SQL 用户定义函数

可将简单 SQL 过程重写为 SQL 用户定义函数,以在数据库管理系统中最大程度地提高性能。

关于此任务

对于过程和函数而言,它们的例程体都是使用可能包含 SQL PL 的复合块实现的。在过程和函数中,相同 SQL PL 语句包括在由 BEGIN 和 END 关键字绑定的复合块中。

过程

将 SQL 过程转换为 SQL 函数时,有一些事项需要注意:
  • 执行此操作的主要和唯一原因是逻辑仅查询数据时改进例程性能。
  • 在标量函数中,您可能必须声明用于保存返回值的变量,以避免您不能直接向函数的任何输出参数指定值的事实。用户定义标量函数的输出值仅在函数的 RETURN 语句中指定。
  • 如果 SQL 函数将修改数据,那么必须使用 MODIFIES SQL 子句显式创建该函数,以便它可包含修改数据的 SQL 语句。

示例

在以下示例中,将显示逻辑上等价的 SQL 过程和 SQL 标量函数。从功能上看,这两个例程在给定相同输入值的情况下提供相同输出值,但它们以略有不同的方式实现和调用。

  CREATE PROCEDURE GetPrice (IN Vendor CHAR(20), 
                             IN Pid INT, 
                             OUT price DECIMAL(10,3)) 
  LANGUAGE SQL 
  BEGIN 
  
    IF Vendor = 'Vendor 1' 
     THEN SET price = (SELECT ProdPrice FROM V1Table WHERE Id = Pid); 
    ELSE IF Vendor = 'Vendor 2' 
     THEN SET price = (SELECT Price FROM V2Table 
	                   WHERE Pid = GetPrice.Pid); 
    END IF; 
  END 
此过程接收两个输入参数值,并返回输出参数值,输出参数值是根据输入参数值有条件确定的。它使用 IF 语句。此 SQL 过程通过执行 CALL 语句调用。例如,可通过 CLP 执行以下操作:

  CALL GetPrice( 'Vendor 1',  9456, ?)
SQL 过程可重写为逻辑上等价的 SQL 表函数,如下所示:

  CREATE FUNCTION GetPrice (Vendor CHAR(20), Pid INT)  
      RETURNS  DECIMAL(10,3) 
  LANGUAGE SQL  MODIFIES SQL
  BEGIN 
    DECLARE price DECIMAL(10,3); 

    IF Vendor = 'Vendor 1' 
      THEN SET price = (SELECT ProdPrice FROM V1Table WHERE Id = Pid); 
    ELSE IF Vendor = 'Vendor 2' 
      THEN SET price = (SELECT Price FROM V2Table 
      			      WHERE Pid = GetPrice.Pid); 
    END IF; 
  
    RETURN price; 
  END 

此函数接收两个输入参数值,并根据输入参数值有条件返回单个标量值。它需要声明并使用局部变量 price 来保存要返回的值直到函数返回,而 SQL 过程可将输出参数用作变量。从功能上看,这两个例程执行相同逻辑。

当然现在其中每个例程的执行接口不同。与简单地通过 CALL 语句调用 SQL 过程不同,SQL 函数必须在允许使用表达式的 SQL 语句中调用。在大多数情况下,这不是问题,如果有意立即操作例程返回的数据,这可能实际上有益。以下是有关如何调用 SQL 函数的两个示例。

可使用 VALUES 语句对它进行调用:

  VALUES (GetPrice('Vendor 1', 9456))      
还可在 SELECT 语句中对它进行调用,例如,可能从表中查询值并根据函数结果过滤行:

  SELECT VName FROM Vendors WHERE GetPrice(Vname, Pid) < 10