如何从事务块中的 INSERT 语句中获取 return 值?

How to return value from INSERT statement in transaction block?

我的目标是returntransaction_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';

RETURNING 子句在事务级别不起作用,它在行级别起作用。为处理的每一行返回一行。此外,该子句还需要有效的 select、so * 或列名。尝试:

 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;

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;
});