【问题标题】:An unexpected token "SELECT" SQL CODE =-104, SQLSTATE=42601, DRIVER=3.69.66意外标记“SELECT”SQL CODE =-104,SQLSTATE=42601,DRIVER=3.69.66
【发布时间】:2021-04-29 21:36:07
【问题描述】:

我有一个存储过程,我需要将它从 Sybase SQL 更改为 DB2 SQL。以下代码适用于 Sybase SQL。

CREATE PROC TAS_TEST
(
    @LOGIN_ID VARCHAR(20),
    @NAME     VARCHAR(100),
    @C_NAME   VARCHAR(100),
    @USER     VARCHAR(20),
    @DEBUG    BIT_FLAG=0
)
AS
BEGIN

    DECLARE @TOKEN_EXPIRY_DATE DATETIME,
        @TOKEN VARCHAR(36),
        @ERR INT,
        @ERROR_MSG VARCHAR(200)
        
    SET @LOGIN_ID = LTRIM(RTRIM(@LOGIN_ID))
    
    IF @LOGIN_ID IS NULL
    BEGIN
        RAISEERROR 20000 'LOGIN ID IS MUST:[%1!]',@LOGIN_ID
        RETURN -1
    END
    IF @NAME IS NULL
    BEGIN
        RAISEERROR 20000 'NAME IS MUST:[%1!]',@NAME
        RETURN -1
    END
    IF @C_NAME IS NULL
    BEGIN
        RAISEERROR 20000 'C_NAME IS MUST:[%1!]',@C_NAME
        RETURN -1
    END
    IF @USER IS NULL
    BEGIN
        RAISEERROR 20000 'USER IS MUST:[%1!]',@USER
        RETURN -1
    END
    
    SELECT
        @TOKEN = TOKEN,
        @TOKEN_EXPIRY_DATE = TOKEN_EXPIRY_DATE
    FROM TOKEN_DETAILS
    WHERE
        LOGIN_ID = @LOGIN_ID and
        NAME = @NAME and
        C_NAME = @C_NAME
        
    
    IF(@TOKEN IS NULL)
    BEGIN
        IF @DEBUG = 1 BEGIN
            PRINT "No token exists"
        END
        
        SELECT @TOKEN = NEWID(1)
        SELECT @TOKEN_EXPIRY_DATE = DATEADD(HOUR,12,GETUTCDATE())
        
        INSERT INTO TOKEN_DETAILS(
            LOGIN_ID,
            TOKEN,
            NAME,
            C_NAME,
            TOKEN_EXPIRY_DATE,
            CREATED_DATE,
            CREATED_BY
        )VALUES(
            @LOGIN_ID,
            @TOKEN,
            @NAME,
            @C_NAME,
            @TOKEN_EXPIRY_DATE,
            GETUTCDATE(),
            @USER
        )
        IF(@@ERROR !=0 )
        BEGIN
            SELECT @ERROR_MSG = CONVERT(CHAR(26),GETDATE(),109)+
            " - Error while inserting - "+ CONVERT(VARCHAR,@@ERROR)
            RAISEERROR 30000 @ERROR_MSG
        RETURN -1
        END
    END
    
    ELSE IF(@TOKEN_EXPIRY_DATE < GETUTCDATE())
    BEGIN
        IF @DEBUG = 1 BEGIN
            PRINT "TOKEN EXPIRES"
        END
        
        SELECT @TOKEN = NEWID(1)
        SELECT @TOKEN_EXPIRY_DATE = DATEADD(HOUR,12,GETUTCDATE())
        
        UPDATE
            TOKEN_DETAILS
        SET
            TOKEN = @TOKEN,
            TOKEN_EXPIRY_DATE = @TOKEN_EXPIRY_DATE
        WHERE
            LOGIN_ID = @LOGIN_ID and
            NAME = @NAME and
            C_NAME = @C_NAME
            
        IF(@@ERROR !=0 )
        BEGIN
            SELECT @ERROR_MSG = CONVERT(CHAR(26),GETDATE(),109)+
            " - Error while UPDATING - "+ CONVERT(VARCHAR,@@ERROR)
            RAISEERROR 30000 @ERROR_MSG
        RETURN -1
        END
    END
    
    ELSE IF @DEBUG = 1 
    BEGIN
        PRINT "TOKEN EXIST"
    END
    SELECT @TOKEN AS 'TOKEN', @TOKEN_EXPIRY_DATE AS 'TOKEN_EXPIRY_DATE'
END
GO

GRANT EXECUTE TAS_TEST TO ADMIN
GO

这是我为上述 Sybase SQL 编写的转换后的 DB2 SQL。

CREATE OR REPLACE PROCEDURE TAS_TEST
(
    LOGIN_ID VARCHAR(20),
    NAME      VARCHAR(100),
    C_NAME    VARCHAR(100),
    USER      VARCHAR(20),
    DEBUG     SMALLINT DEFAULT 0
)

LANGUAGE SQL

BEGIN

DECLARE TOKEN_EXPIRY_DATE TIMESTAMP;
DECLARE TOKEN VARCHAR(36);
DECLARE ERR INT;
DECLARE ERROR_MSG VARCHAR(200);

SET LOGIN_ID = TRIM(LOGIN_ID);

IF LOGIN_ID IS NULL THEN
    SIGNAL SQLSTATE VALUE '20000'
    SET MESSAGE_TEXT = 'LOGIN ID IS MUST:';
END IF;
IF NAME IS NULL THEN
    SIGNAL SQLSTATE VALUE '20000'
    SET MESSAGE_TEXT = 'NAME IS MUST:';
END IF;
IF C_NAME IS NULL THEN
    SIGNAL SQLSTATE VALUE '20000'
    SET MESSAGE_TEXT = 'C_NAME IS MUST:';
END IF;
IF USER IS NULL THEN
    SIGNAL SQLSTATE VALUE '20000'
    SET MESSAGE_TEXT = 'USER IS MUST:';
END IF;


SELECT
    TOKEN = TOKEN,
    TOKEN_EXPIRY_DATE = TOKEN_EXPIRY_DATE
FROM TOKEN_DETAILS
WHERE
    LOGIN_ID = LOGIN_ID and
    NAME = NAME and
    C_NAME = C_NAME;
    
IF(TOKEN IS NULL) THEN
BEGIN
    IF DEBUG = 1 THEN
        PRINT 'No token exists';
    END IF;
    
    SELECT TOKEN = GENERATE_UNIQUE(1) FROM SYSIBM.SYSDUMMY1;
    SELECT TOKEN_EXPIRY_DATE = TIMESTAMPADD(CURRENT_TIMESTAMP) FROM SYSIBM.SYSDUMMY1;
    
    INSERT INTO TOKEN_DETAILS(
        LOGIN_ID,
        TOKEN,
        NAME,
        C_NAME,
        TOKEN_EXPIRY_DATE,
        CREATED_DATE,
        CREATED_BY
    )VALUES(
        LOGIN_ID,
        TOKEN,
        NAME,
        C_NAME,
        TOKEN_EXPIRY_DATE,
        CURRENT_TIMESTAMP,
        USER
    );
END;
END IF;

IF(TOKEN_EXPIRY_DATE < CURRENT_TIMESTAMP)
BEGIN
    IF DEBUG = 1 THEN
        PRINT "TOKEN EXPIRES, UPDATING";
    END IF;
    
    SELECT TOKEN = GENERATE_UNIQUE(1) FROM SYSIBM.SYSDUMMY1;
    SELECT TOKEN_EXPIRY_DATE = TIMESTAMPADD(CURRENT_TIMESTAMP) FROM SYSIBM.SYSDUMMY1;
    
    UPDATE
        TOKEN_DETAILS
    SET
        TOKEN = TOKEN,
        TOKEN_EXPIRY_DATE = TOKEN_EXPIRY_DATE
    WHERE
        LOGIN_ID = LOGIN_ID and
        NAME = NAME and
        C_NAME = C_NAME;
END;
END IF;

IF (DEBUG = 1) THEN 
BEGIN
    PRINT "TOKEN EXIST";
END;
END IF;
SELECT TOKEN, TOKEN_EXPIRY_DATE FROM SYSIBM.SYSDUMMY1;
END;

GRANT EXECUTE TAS_TEST TO ADMIN;

在运行上述 db2 查询时,出现此错误。

[42601][-104] 在“”之后发现了意外的标记“SELECT”。预期可能包括“END IF”.. SQL CODE =-104, SQLSTATE=42601, DRIVER=3.69.66

谁能帮我找出我做错的地方。会有很大帮助的。

【问题讨论】:

  • 为什么要标记 SQL Server?
  • 您的代码至少有 10 个错误会阻止编译。请指定您的 Db2-server PLATFORM(即 Z/OS、i 系列、Linux/Unix/Windows),并指定 Db2-server 的版本
  • 另外,您需要更改语句分隔符。您不能使用 ; 将您的 CREATE PROCEDURE 语句与后续语句 ibm.com/support/knowledgecenter/SSEPGG_11.5.0/… 分开
  • @mao - Db2 服务器平台 - LUW 和版本是 v10.1.0.6
  • @PaulVernon - 我使用 @ 作为分隔符。

标签: sql database db2 sybase db2-luw


【解决方案1】:

您的代码中有多个问题会阻止在 Db2 上编译。

考虑接受一些关于 ANSI SQL PL(Db2-LUW 使用的语法)的教育。

从 IBM 在 Db2-LUW 服务器的示例目录、Db2-LUW 知识中心和 github 上提供的许多示例 SQL PL 过程中学习。

让有能力或经验丰富的 SQL PL 开发人员审查您的代码。

您的个人资料显示“CapGemini 顾问”,因此您的公司应该具备这些技能。

请记住,Stackoverflow 不是代码编写服务。

一些建议:

  • PRINT 语句在 ANSI SQL PL 中无效。对于 Db2-LUW,许多人使用调试 call dbms_output.put_line('some message');set serveroutput on 进行会话。

  • 使用SET 语句从函数中分配变量。示例:SET v_token = GENERATE_UNIQUE();

  • 仅当您需要特定于块的异常处理或条件处理时才使用内部 BEGIN..END 块。不必使用 BEGIN...END 块来分隔 IF 内的一组语句。

  • 不要使用保留字作为变量名或列名(如USER

  • 考虑对参数和局部变量使用命名约定。命名约定可能会使用一些指示符来表明名称是本地的 v_* ,或者表明名称是例程 p_* 的参数。

  • 在例程中,使用SELECT ... INTO ... 从单例选择中分配变量。

  • 要为结果集列设置别名,请使用“colName AS colAlias”语法

  • 要返回结果集,请在签名中明确指定,并在末尾声明并打开一个游标。您的线路SELECT TOKEN, TOKEN_EXPIRY_DATE FROM SYSIBM.SYSDUMMY1; 无效。

  • Db2 GENERATE_UNIQUE() 函数不接受参数。

  • 考虑使用CURRENT TIMESTAMP + 12 HOURS,而不是 TIMESTAMPADD。

  • 要在查询后测试是否缺少行,请显式测试 SQLCODE 100 或使用条件处理程序。

  • 考虑将 upsert 作为单个 MERGE 语句的一部分,这可以使代码更清晰并简化错误检测和恢复。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-02
    • 1970-01-01
    • 1970-01-01
    • 2016-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多