未修改主表时获取插入的行数

Man*_*bes 5 postgresql partitioning plpgsql

我有一个分区表,其中数据仅驻留在子表中。主表有一个插入触发器,可以将插入的数据分配到适当的子表中。

现在,我需要创建一个 PL/pgSQL 过程,该过程从(主)表中选择一些数据并使用一些更改的值重新插入它。

通常我会使用ROW_COUNT诊断变量并完成它。问题是 ROW_COUNT 始终为 0,因为主表中没有插入任何内容(触发器在途中捕获并重定向插入)。

我的下一个想法是做类似的事情

WITH inserted AS (
  INSERT INTO master (...) SELECT ... FROM master WHERE ... RETURNING master.field
) SELECT count(*) FROM inserted INTO rowcount;
Run Code Online (Sandbox Code Playgroud)

但是,再次,rowcount 总是最终为 0,因为没有实际插入到主表中。

如果我做

WITH insertable AS (
  SELECT ... FROM master WHERE ...
), blah AS (
  SELECT count(*) INTO rowcount FROM insertable
) INSERT INTO master SELECT * FROM insertable;
Run Code Online (Sandbox Code Playgroud)

然后 Postgresql 抱怨说:

错误:INTO 与无法返回数据的命令一起使用

SQL 状态:42601

等等...

如果是我最后的代码提取,我如何将行数inserted放入rowcount我的程序中的变量中,然后我可以用它来做东西™?或者有没有其他方法可以检索插入到(继承自)主表中的行数?

Eze*_*nay 1

如果这对您来说仍然是理想的(尽管不是那么重要),那么这是一个解决方案:

CREATE TABLE rows_affected_in_session (
  session_pid int NOT NULL,
  session_time timestamptz NOT NULL,
  table_name text NOT NULL,
  rows_affected int NOT NULL,
  PRIMARY KEY (session_pid, session_time, table_name));

CREATE OR REPLACE FUNCTION f_update_rows_affected_in_session (p_table regclass, p_rows_affected int) RETURNS void AS $BODY$
BEGIN
  IF NOT EXISTS (SELECT 1 FROM rows_affected_in_session WHERE session_pid = pg_backend_pid() AND session_time = current_timestamp AND table_name = p_table::text) THEN
    INSERT INTO rows_affected_in_session (session_pid, session_time, table_name, rows_affected)
    VALUES (pg_backend_pid(), current_timestamp, p_table::text, p_rows_affected);
  ELSE
    UPDATE rows_affected_in_session SET rows_affected = rows_affected + p_rows_affected
    WHERE session_pid = pg_backend_pid() AND session_time = current_timestamp AND table_name = p_table::text; 
  END IF;
END;
$BODY$ LANGUAGE PLPGSQL SECURITY DEFINER;

CREATE OR REPLACE FUNCTION f_rows_affected_in_session() RETURNS TABLE (table_name text, rows_affected int) AS $BODY$
  SELECT table_name, rows_affected
  FROM rows_affected_in_session
  WHERE session_pid = pg_backend_pid() AND session_time = current_timestamp
  ORDER BY 1
$BODY$ LANGUAGE SQL SECURITY DEFINER;
Run Code Online (Sandbox Code Playgroud)

f_update_rows_affected_in_session(<table>, <rows_affected>)您可以通过在触发器中每次成功插入后调用该函数来使用它(您可以使用 ROW_COUNT 诊断),然后使用该函数f_rows_affected_in_session()检索会话中受影响的行(您可以在其中准确确定哪些子表受到影响,或者求和总计结果)。例子:

SELECT f_update_rows_affected_in_session('mytable'::regclass, 1);
SELECT f_update_rows_affected_in_session('mytable'::regclass, 1);
SELECT f_update_rows_affected_in_session('mytable'::regclass, 1);
SELECT * FROM f_rows_affected_in_session();
Run Code Online (Sandbox Code Playgroud)