HSQLDB存储过程错误:尝试分配给不可更新的列

时间:2014-12-11 01:19:54

标签: sql stored-procedures syntax-error hsqldb

我正在使用HSQLDB 2.3.2,并且在尝试创建存储过程时遇到了一个奇怪的错误。

我的addresses表:

CREATE TABLE IF NOT EXISTS addresses (
    address_id                  INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL PRIMARY KEY,
    address_line_1              NVARCHAR(500) NOT NULL,
    address_line_2              NVARCHAR(500),
    address_city                NVARCHAR(100) NOT NULL,
    address_postal_code         NVARCHAR(25) NOT NULL,

    CONSTRAINT uc_addresses UNIQUE (address_line_1, address_city)
)

填充它的插入内容:

INSERT INTO addresses (
    address_line_1,
    address_city,
    address_postal_code
) VALUES (
    '123 Test Blvd.', 'Testville', '11111'
)

我的处理:

CREATE PROCEDURE sp_get_address_by_id(
        IN address_id INTEGER,
        OUT address_id  INTEGER,
        OUT address_line_1 NVARCHAR(500),
        OUT address_line_2 NVARCHAR(500),
        OUT address_city NVARCHAR(100),
        OUT address_postal_code NVARCHAR(25))
    READS SQL DATA
    BEGIN ATOMIC
        SELECT
            a.address_id,
            a.address_line_1,
            a.address_line_2,
            a.address_city,
            a.address_postal_code
        INTO
            address_id,
            address_line_1,
            address_line_2,
            address_city,
            address_postal_code
        FROM
            addresses a 
        WHERE
            a.address_id = address_id;
    END

当我跑步时,我得到:

Error: attempt to assign to non-updatable column
SQLState:  0U000
ErrorCode: -2500

问题:

  1. 我的proc有什么问题(产生此错误的原因是什么)?
  2. 我实际上正在寻找一个CREATE IF NOT EXISTS类型的声明,所以我可以一遍又一遍地运行这个脚本,如果它不存在,程序将只创建一次。会发生这种情况还是我需要更改语法来完成IF NOT EXISTS

3 个答案:

答案 0 :(得分:3)

根据hsqldb文档,尝试以下语法 http://hsqldb.org/doc/2.0/guide/sqlroutines-chapt.html#src_psm_assignment

  

SET语句用于赋值。它可以灵活使用   行或单个值。

同时将address_id参数更改为键入INOUT并删除重复的address_id参数行。

CREATE PROCEDURE sp_get_address_by_id(
    INOUT address_id INTEGER,
    OUT address_line_1 NVARCHAR(500),
    OUT address_line_2 NVARCHAR(500),
    OUT address_city NVARCHAR(100),
    OUT address_postal_code NVARCHAR(25))
READS SQL DATA
BEGIN ATOMIC
    SET (address_id,
        address_line_1,
        address_line_2,
        address_city,
        address_postal_code)
    = 
    (
    SELECT
        a.address_id,
        a.address_line_1,
        a.address_line_2,
        a.address_city,
        a.address_postal_code
    FROM
        addresses a 
    WHERE
        a.address_id = address_id
    );
END

如果要删除已存在的过程,可以尝试将其添加为脚本中的第一个语句,以便可以多次重新运行该脚本。您可以在documentation搜索<specific routine designator>以获取更多信息。

DROP SPECIFIC PROCEDURE sp_get_address_by_id IF EXISTS;

答案 1 :(得分:1)

在您的程序中,您有两个具有相同名称的参数:

IN address_id INTEGER,
OUT address_id  INTEGER,

当您在程序正文中提及address_id时,可能会出现问题 你应该使用:

INOUT address_id  INTEGER,

而不是这两行。

回答你的第二个问题:
为什么要在不重建过程的情况下反复运行此脚本?当某些内容发生变化时,再次运行此脚本是有意义的。

  • 如果您不打算更改此过程,但想要更改脚本中的其他内容,那么您可能只需将此过程移至其他脚本并仅运行一次
  • 如果您计划更改程序正文,则应每次都重建。所以你应该使用CREATE OR REPLACE PROCEDURE

答案 2 :(得分:0)

对于粉丝,如果您这样做,则会抛出相同的错误消息:

 PreparedStatement selectStmt = conn.prepareStatement(query);
 ResultSet rs = selectStmt.executeQuery()) {
 rs.next();
 rs.updateLong("column", value); // boom

一个解决方法是使用这种风格:

 PreparedStatement selectStmt = 
    conn.prepareStatement(query, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);