【问题标题】:Get values from RETURNING * within a transaction从事务中的 RETURNING * 获取值
【发布时间】:2012-09-17 16:53:32
【问题描述】:

当我在 begin;commit; 事务中有两个 INSERT SQL 语句(见下文)时,RETURNING * 不会返回任何内容,但如果我取出 begin;commit; @ 987654327@ 确实返回插入的记录。
如何让RETURNING * 在事务中工作?

BEGIN;

INSERT INTO gis_field_configuration
   (level_unique_name, level_name_caption, use_for_charts, use_as_displayby, 
    displayby_label, data_type, level_help_text)
VALUES (
    '[john].[john]',
    'john',
    'false',
    'false',
    '',
    'text',
    'help text'
);

INSERT INTO gis_field_configuration_bycube
   (cube, level_unique_name)
VALUES (
    'Instruments',
    '[john].[john]'
) RETURNING *;

COMMIT;

【问题讨论】:

  • 你是如何运行查询的?如果您分批发送它们,您将不会收到任何回复,但是如果您像往常一样发送它们,则应该检查实际查询的结果,并在获得结果后提交... ?
  • 您的 RETURNING 语句实际上需要什么?序列号列的值?如果是这样,您可以简化,只需 select curval('the_relevant_sequence')

标签: sql postgresql transactions sql-insert


【解决方案1】:

一种方法是使用data-modifying CTE 并将两个INSERTs 打包到一个命令中。需要 PostgreSQL 9.1 或更高版本:

WITH x AS (
   INSERT INTO gis_field_configuration (level_unique_name, level_name_caption
                ,use_for_charts, use_as_displayby, displayby_label, data_type
                ,level_help_text)
   VALUES (
       '[john].[john]',
       'john',
       'false',
       'false',
       '',
       'text',
       'help text'
   )
   )
INSERT INTO gis_field_configuration_bycube
   (cube, level_unique_name)
VALUES (
    'Instruments',
    '[john].[john]'
    )
RETURNING *;

但是,无论如何,您确实可以通过RETURNING * 取回值。只需在发送COMMIT 之前阅读它们。作为批次发送,仅返回来自 last 命令的结果 - 如果您作为一个批次发送 所有 命令,这将是 COMMIT 的结果。

保留COMMIT;,直到收到第二个INSERT 的结果。


在 plpgsql 函数中

一个函数在事务中自动运行。您不需要明确的 BEGIN / COMMIT。要重用您从 INSERT 获取的值,请使用 RETURNING *expressions* INTO [STRICT] *target*

考虑这个简单的演示:

CREATE TABLE foo (foo_id serial, bar text);

CREATE OR REPLACE FUNCTION f_foo()
  RETURNS void LANGUAGE plpgsql AS
$BODY$
DECLARE
   foo_var foo; -- type name = table name, fits return type of RETURNING *
   -- or use a generic type record
BEGIN

   INSERT INTO foo (bar)
   VALUES ('baz')
   RETURNING *
   INTO foo_var;

   RAISE NOTICE 'New id is: %', foo_var.foo_id;

   -- do stuff with foo_var

   END;
   $BODY$;

SELECT f_foo();

【讨论】:

  • 我运行了上面的 WITH x AS ( 语句,我得到了以下错误:错误:在“INSERT”第 2 行或附近出现语法错误:INSERT INTO gis_field_configuration (level_unique_name, l... ^ ** ******** 错误 ********** 错误:“INSERT”处或附近的语法错误 SQL 状态:42601 字符:17
  • @JohnMitchell:你运行的是哪个 PostgreSQL 版本? 9.1 引入了可更新的 CTE
  • 我的 postgres 版本是 8.4.9,所以我想我不能使用 WITH 命令。
  • @JohnMitchell:在这种情况下,请考虑保留COMMIT;,直到您收到返回值之后。
  • 如何将第二次插入的结果分配给临时变量,以便在 COMMIT 之后使用;声明?
【解决方案2】:

我怀疑您将所有这些语句作为您语言的客户端驱动程序中的单个文本字符串运行。如果是这种情况,返回给客户端的结果将是您发送的语句块中的 last statement 返回的结果。在这种情况下,这就是 COMMIT 语句,它没有结果,所以你不会得到任何结果。

逐个运行每个语句,它应该可以正常工作。我无法给出更详细的示例,因为您没有提到您使用的是哪种语言。

这是一个 Python/psycopg 示例。当我尝试获取结果时,将所有 SQL 发送到一个 blob 中的第一种方法会导致异常,因为commit 不会产生结果。第二个示例,我分别运行每个语句并在我 commit 之前获得 select 的结果,工作正常。

import psycopg2

conn = psycopg2.connect("dbname=regress")
curs = conn.cursor();

# All in one blob
try:
    curs.execute("BEGIN; SELECT generate_series(1,10); COMMIT;")
    print(curs.fetchall())
except (psycopg2.ProgrammingError) as ex:
    print("Failed: ", ex)

# vs one-by-one
curs.execute("BEGIN;")
curs.execute("SELECT x.* FROM generate_series(1,10) x;")
print(curs.fetchall())
curs.execute("COMMIT;")

输出:

$ python3 test.py 
Failed:  no results to fetch
[(1,), (2,), (3,), (4,), (5,), (6,), (7,), (8,), (9,), (10,)]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-09
    • 1970-01-01
    • 2015-02-24
    • 2021-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多