【问题标题】:Returning a column from an INSERTED record via an updateable view通过可更新视图从 INSERTED 记录中返回列
【发布时间】:2020-05-07 07:18:39
【问题描述】:

我需要允许我的用户更新和插入视图。重要的是,当他们插入时,他们需要能够从插入的行返回新值,但是现在他们得到 NULL。它必须是一个视图,就像在视图的 SELECT 中一样,它需要能够返回作为连接结果的值。

我的基础表定义:

CREATE TABLE my_assets (
    asset_id bigserial not null primary key,
    asset_price NUMERIC(32,10) -- This will vary constantly via an independent process
);

CREATE TABLE my_transactions (
    id bigserial not null primary key,
    asset_id bigint not null REFERENCES my_assets(asset_id),
    some_text varchar(100)
);
INSERT INTO my_assets(asset_price) SELECT 100 as asset_price;

显示表格结果的我的视图:

CREATE VIEW my_transactions_view AS
SELECT tx.id, tx.asset_id, tx.some_text, a.asset_price
FROM my_transactions tx
JOIN my_assets a ON tx.asset_id = a.asset_id

我的触发器允许插入my_transactions_view

CREATE OR REPLACE FUNCTION trigfx_insert_to_my_transactions_view()
RETURNS trigger AS
    $BODY$
BEGIN
    INSERT INTO my_transactions(asset_id, some_text)
    SELECT NEW.asset_id, NEW.some_text;
    RETURN NEW;
END
    $BODY$
    LANGUAGE 'plpgsql';

CREATE TRIGGER trig_my_transactions_view INSTEAD OF INSERT on my_transactions_view
FOR EACH ROW EXECUTE PROCEDURE trigfx_insert_to_my_transactions_view();

到目前为止一切顺利。但是,问题来自尝试运行以下 SQL:

INSERT INTO my_transactions_view(asset_id, some_text)
    SELECT 1 as asset_id, 'Hello World' as some_text
    RETURNING id, asset_id, some_text;

返回的表返回ID为NULL,但我想从my_transactions表返回新更新的ID:

|---------------------|------------------|------------------|
|         ID          |     asset_id     |    some_text     |
|---------------------|------------------|------------------|
|        null         |         1        |  Hello World     |
|---------------------|------------------|------------------|

运行后续的SELECT * FROM my_transactions_view 确实会产生更新的结果:

|------------------|------------------|------------------|------------------|
|         ID       |     asset_id     |    some_text     |    asset_price   |
|------------------|------------------|------------------|------------------|
|         1        |         1        |  Hello World     |  100.0000000     |
|------------------|------------------|------------------|------------------|

但我需要在 INSERT 语句的 RETURNING 期间生成它。

谢谢!!!

【问题讨论】:

    标签: sql postgresql plpgsql database-trigger sql-view


    【解决方案1】:

    您可以使用生成的 ID 填充 new 记录:

    CREATE OR REPLACE FUNCTION trigfx_insert_to_my_transactions_view()
    RETURNS trigger AS
        $BODY$
    BEGIN
        INSERT INTO my_transactions(asset_id, some_text)
        values (NEW.asset_id, NEW.some_text);
        new.id := lastval(); --<< this gets the generated id from the transactions table
        RETURN NEW;
    END
    $BODY$
    LANGUAGE plpgsql;
    

    Online example

    您也可以使用currval(pg_get_serial_sequence('my_transactions','id')) 代替lastval()

    【讨论】:

    • 太棒了! new.id := lastval(); 工作得很好。非常感谢!
    • 在后来的测试中,我们遇到了new.id := lastval(); 的错误,请参阅下面的答案以获得最终的解决方案,从而避免额外的函数调用。
    【解决方案2】:

    事实证明,我们可以通过 CTE 中的 SELECT INTO 避免额外的函数调用:

    CREATE OR REPLACE FUNCTION trigfx_insert_to_my_transactions_view()
    RETURNS trigger AS
        $BODY$
    BEGIN
        WITH ins_q as (INSERT INTO my_transactions(asset_id, some_text)
        values (NEW.asset_id, NEW.some_text)
        RETURNING id, asset_id, some_text)
        SELECT ins_q.id, ins_q.asset_id, ins_q.some_text
        INTO NEW.id, NEW.asset_id, NEW.some_text
        FROM ins_q;
        RETURN NEW;
    END
    $BODY$
    LANGUAGE plpgsql;
    

    See online example here. 我在使用 new.id := lastval(); 方法时遇到了初始化错误 (lastval is not yet defined in this session)。

    【讨论】:

      猜你喜欢
      • 2010-12-11
      • 1970-01-01
      • 2020-01-01
      • 2020-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多