Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 12.0.1 » SQL Anywhere 服务器 - SQL 的用法 » 存储过程、触发器、批处理和用户定义的函数

 

过程、触发器、用户定义函数和批处理中使用的 EXECUTE IMMEDIATE

EXECUTE IMMEDIATE 语句允许使用文字字符串(在引号中)和变量的组合来构建语句。例如,以下过程包含创建表的 EXECUTE IMMEDIATE 语句。

CREATE PROCEDURE CreateTableProcedure(
      IN tablename CHAR(128) )
BEGIN
   EXECUTE IMMEDIATE 'CREATE TABLE '
   || tablename
   || '( column1 INT PRIMARY KEY )'
END;

EXECUTE IMMEDIATE 语句可以与返回结果集的查询一起使用。您可将 WITH RESULT SET ON 子句与 EXECUTE IMMEDIATE 语句配合使用,以指示语句返回结果集—缺省行为是语句不返回结果集。指定 WITH RESULT SET ON 或 WITH RESULT SET OFF 同时影响创建过程时和执行过程时所发生的事件。

请考虑以下过程:

CREATE OR REPLACE PROCEDURE test_result_clause()
BEGIN
    EXECUTE IMMEDIATE WITH RESULT SET OFF 'SELECT 1';
END;

当过程定义中不包括 RESULT SET 子句时,数据库服务器将试图确定过程是否生成结果集。在此处,EXECUTE IMMEDIATE 语句指定不生成结果集。因此,数据库服务器定义的过程没有结果集列,并且此过程的 SYSPROCPARM 系统视图中也没有任何行。对此过程的 CALL 执行 DESCRIBE 将不会返回任何结果列。如果嵌入式 SQL 应用程序使用该信息来决定是否要打开游标或执行语句,则其会执行语句,然后返回错误。

作为第二个示例,请考虑上述过程的修改版本:

CREATE OR REPLACE PROCEDURE test_result_clause()
BEGIN
    EXECUTE IMMEDIATE WITH RESULT SET ON 'SELECT 1';
END;

在此处,WITH RESULT SET ON 子句将致使此过程的 SYSPROCPARM 系统视图中存在一个行。数据库服务器不知道结果集的外观—因为过程正在使用 EXECUTE IMMEDIATE—但其知道过程将返回结果集,所以数据库服务器在 SYSPROCPARM 中定义一个虚设的结果集列来表示过程的结果集(其名称为 "expression",类型为 SMALLINT)。请注意,仅创建一个虚设的结果集列;使用 EXECUTE IMMEDIATE 语句时,服务器无法确定各结果集的列的数目和类型。因此,请考虑以下稍做修改的示例:

CREATE OR REPLACE PROCEDURE test_result_clause()
BEGIN
    EXECUTE IMMEDIATE WITH RESULT SET ON 'SELECT 1, 2, 3';
END;

在此,虽然 SELECT 会返回含有三个列的结果集,但服务器仍然仅在 SYSPROCPARM 系统视图中放置一行。因此,以下查询

SELECT * FROM test_result_clause();

失败并生成 SQLCODE -866,因为运行时的结果集特性与 SYSPROCPARM 中的占位符结果不匹配。

要执行上述查询,您可以显式指定结果集列的名称和类型,如下所示:

SELECT * FROM test_result_clause() WITH (x INTEGER, y INTEGER, z INTEGER);

在执行时,如果指定 WITH RESULT SET ON,数据库服务器处理返回结果集的 EXECUTE IMMEDIATE 语句。但是,如果指定 WITH RESULT SET OFF 或省略该子句,则数据库服务器仍会在已分析的字符串参数中查看第一个语句的类型。如果该语句是 SELECT 语句,则其会返回结果集。因此,在上面的第二个示例中:

CREATE OR REPLACE PROCEDURE test_result_clause()
BEGIN
    EXECUTE IMMEDIATE WITH RESULT SET OFF 'SELECT 1';
END;

从 Interactive SQL 中可以成功地调用此过程。但是,如果更改此过程以使其包含批处理,而不是仅包含一个 SELECT 语句:

CREATE OR REPLACE PROCEDURE test_result_clause()
BEGIN
    EXECUTE IMMEDIATE WITH RESULT SET OFF 
    'begin declare v int; set v=1; select v; end';
END;

则对 test_result_clause 过程的 CALL 将会返回错误(SQLCODE -946、SQLSTATE 09W03)。

最后一个示例说明您如何将 SELECT 语句构造为某个过程中的 EXECUTE IMMEDIATE 语句的参数,并使该过程返回结果集。



CREATE PROCEDURE DynamicResult(
   IN Columns LONG VARCHAR,
   IN TableName CHAR(128),
   IN Restriction LONG VARCHAR DEFAULT NULL )
BEGIN
    DECLARE Command LONG VARCHAR;
    SET Command = 'SELECT ' || Columns || ' FROM ' || TableName;
    IF ISNULL( Restriction,'') <> '' THEN
         SET Command = Command || ' WHERE ' || Restriction;
    END IF;
    EXECUTE IMMEDIATE WITH RESULT SET ON Command;
END;

如果按如下方式调用该过程:

CALL DynamicResult(
   'table_id,table_name',
   'SYSTAB',
   'table_id <= 10');

它将生成以下结果:

table_id table_name
1 ISYSTAB
2 ISYSTABCOL
3 ISYSIDX
... ...

上述 CALL 将正确返回结果集,即使过程利用 EXECUTE IMMEDIATE 也是如此。一些服务器 API(例如 ODBC)将请求与 PREPARE-DESCRIBE-EXECUTE-OR-OPEN 结合使用,从而根据其是否返回结果集来决定是执行语句还是打开语句。如果打开语句,API 或应用程序可随即发出 DESCRIBE CURSOR 来确定实际结果集的外观,而不是依赖于创建过程时 SYSPROCPARM 系统视图的内容。DBISQL 和 DBISQLC 均使用此技术。在上述情况下,对以上过程的 CALL 将会正确执行。但是,依赖于语句的 DESCRIBE 结果的应用程序接口将无法处理任意语句。

在原子复合语句中,不能使用导致 COMMIT(提交)的 EXECUTE IMMEDIATE 语句,因为在该上下文中不允许 COMMIT。

 另请参见