【问题标题】:How to return value from INSERT statement in transaction block?如何从事务块中的 INSERT 语句返回值?
【发布时间】:2020-04-06 18:11:41
【问题描述】:

我的目标是返回 transaction_start 值。 尝试了 RETURNING 关键字。

但在事务中它不起作用。结果没有错误。结果只是不包含任何数据。

还有其他方法可以实现这个目标吗?

BEGIN;
DELETE FROM table_for_tests WHERE item_id = '142';
INSERT INTO table_for_tests (item_id, valid, key, value) 
VALUES 
  ('142', tstzrange('1970-01-01T03:00', '1970-01-01T03:00:00.000100', '[)'), 'key1', 'modified value1'), 
  ('142', tstzrange('1970-01-01T03:00', '1970-01-01T03:00:00.000100', '[)'), 'key2', 'modified value2') 
RETURNING lower(transaction) as transaction_start;
COMMIT;

UPD

table_for_tests 架构:

id         | item_id  | valid               | transaction        | key           | value 
BIGSERIAL  | BIGINT   | TSTZRANGE NOT NULL  | TSTZRANGE NOT NULL | VARCHAR(255)  | VARCHAR(255) 

transaction 列在执行 INSERT、UPDATE 或 DELETE 操作时由触发器(posgresql temporal_tables 扩展)自动填充。

触发器是由这段代码创建的:

CREATE TRIGGER versioning_trigger BEFORE INSERT OR UPDATE OR DELETE ON 
table_for_tests FOR EACH ROW 
EXECUTE PROCEDURE versioning('transaction', 'table_for_tests_history', true);

UPD 2

trigger function (versioning) 的源代码,来自 pgAdmin III:

-- Function: public.versioning()

-- DROP FUNCTION public.versioning();

CREATE OR REPLACE FUNCTION public.versioning()
  RETURNS trigger AS
'$libdir/temporal_tables', 'versioning'
  LANGUAGE c VOLATILE STRICT
  COST 1;
ALTER FUNCTION public.versioning()
  OWNER TO postgres;
GRANT EXECUTE ON FUNCTION public.versioning() TO postgres;
REVOKE ALL ON FUNCTION public.versioning() FROM public;
COMMENT ON FUNCTION public.versioning() IS 'System-period temporal table trigger';

【问题讨论】:

  • 描述“不工作”。
  • '不工作'意味着在事务中执行查询后它没有返回值。我试图返回“id”(主键)——也没有返回值。
  • edit你的问题并添加触发器的源代码函数 (versioning)
  • @a_horse_with_no_name 我已经从 pgAdmin SQL 窗格中添加了触发函数(版本控制)的源代码,但由于它是 temporal_tables 扩展内的 C 语言库,所以无法进入。
  • 好的,这不是关于 PostgreSQL 的问题,而是关于扩展的问题。你应该ask作者。

标签: postgresql temporal-tables


【解决方案1】:

JOOQ解决了这个问题。

它有DSLContexttransactionResult() 方法。

例子:

KeyValuesRecord record = context.transactionResult(tx -> {

tx.dsl().deleteFrom(KEY_VALUES)
            .where(KEY_VALUES.ITEM_ID.eq('142'))
            .execute();

KeyValuesRecord insertResult = tx.dsl().insertInto(KEY_VALUES, KEY_VALUES.ITEM_ID, KEY_VALUES.VALID, KEY_VALUES.VALUE)
        .values(itemId, range, value)
        .returning(KEY_VALUES.TRANSACTION)
        .fetchOne(); 

return insertResult;
});

【讨论】:

    【解决方案2】:

    RETURNING 子句不适用于事务级别,它适用于行级别。为处理的每一行返回一行。此外,该子句需要有效的选择,例如 * 或列名。试试:

     insert into table_for_tests (item_id, valid, key, value) 
           values 
             ('142', tstzrange('1970-01-01t03:00', '1970-01-01T03:00:00.000100', '[)'), 'key1', 'modified value1'), 
             ('142', tstzrange('1970-01-01t03:00', '1970-01-01T03:00:00.000100', '[)'), 'key2', 'modified value2') 
          returning lower(valid) as transaction_start;
    

    或许:

    with do_ins  as  
         ( insert into table_for_tests (item_id, valid, key, value) 
           values 
             ('142', tstzrange('1970-01-01T03:00', '1970-01-01T03:00:00.000100', '[)'), 'key1', 'modified value1'), 
             ('142', tstzrange('1970-01-01T03:00', '1970-01-01T03:00:00.000100', '[)'), 'key2', 'modified value2') 
          returning lower(valid) as transaction_start
        )
    select distinct transaction_start, count(*) over (partition by transaction_start)
      from do_ins;
    

    【讨论】:

    • 您的第二个变体可以作为 BEGIN COMMIT 块的一部分执行吗?
    • 在事务中尝试了您的代码(开始提交)。查询未返回任何结果。
    • 您需要准确发布您正在运行的内容以及如何运行的说明。而且由于您不争辩任何结果并且不提供错误消息,那么最好提供minimal reproducible example
    猜你喜欢
    • 2016-12-25
    • 2016-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-19
    • 1970-01-01
    相关资源
    最近更新 更多