【问题标题】:Add schema name to dynamic Postgres query将模式名称添加到动态 Postgres 查询
【发布时间】:2016-08-15 04:32:13
【问题描述】:

我的数据库使用 Postgres 模式为用户提供分离的多租户环境。每个架构都有相同表的副本。

我有一个特定的查询,我需要跨模式加入,返回记录列表(在本例中为children)。我通过动态 SQL 查询来实现这一点,如下所示。但是,我想在每个结果中添加一列,指定该行来自的架构名称。

当前动态查询

(架构的样子:OPERATOR_SCHEMA_my-great-company)

CREATE OR REPLACE FUNCTION all_children_dynamic() RETURNS SETOF children AS $$
DECLARE
  schema RECORD;
BEGIN
  FOR schema IN EXECUTE
    format(
      'SELECT schema_name FROM information_schema.schemata WHERE left(schema_name, 16) = %L',
      'OPERATOR_SCHEMA_'
    )
  LOOP
    RETURN QUERY EXECUTE
      format('SELECT * FROM %I.children', schema.schema_name);
  END LOOP;
END;
$$ LANGUAGE plpgsql;

--------

-- Usage: SELECT "id", "name" FROM all_children_dynamic();

这会返回类似:

-------------
| id | name |
| 1  | Bob  |
| 2  | Joe  |
-------------

而我希望它返回如下内容:

-------------------------------
| id | name | schema_name     |
| 1  | Bob  | darcy's-store   |
| 2  | Joe  | bob's-4th-store |
-------------------------------

需要注意的是,模式名称是用户定义的,并且可以在其中包含引号。

如何为每个孩子添加相关的架构名称?

我尝试了以下几种变体:

LOOP
   RETURN QUERY EXECUTE
     format('SELECT %s AS schema_name, * FROM %1$I.children', schema.schema_name);
END LOOP;

但我在格式化等方面遇到了一些问题。我应该在这里使用一些 quote_X 功能。

我对 Postgres(以及一般的数据库)不是很了解,因此感谢您的耐心等待!

更新

以下是我在几个变体中得到的确切错误。

Input:
format('SELECT %s AS schema_name, * FROM %1$I.children', schema.schema_name);

ERROR:  column "operator_schema_don" does not exist
LINE 1: SELECT OPERATOR_SCHEMA_don-t-display-data AS schema_name, * ...
QUERY:  SELECT OPERATOR_SCHEMA_don-t-display-data AS schema_name, * FROM "OPERATOR_SCHEMA_don-t-display-data".children

Input:
format('SELECT %s AS schema_name, * FROM %I.children', quote_literal(schema.schema_name), schema.schema_name);

ERROR:  structure of query does not match function result type
DETAIL:  Returned type unknown does not match expected type uuid in column 1.

更新 2

我越来越近了,但还没有到。

CREATE OR REPLACE FUNCTION all_children_dynamic() RETURNS TABLE (id uuid, schema_name varchar) AS $$
DECLARE
  schema RECORD;
BEGIN
  FOR schema IN EXECUTE
    format(
      'SELECT schema_name FROM information_schema.schemata WHERE left(schema_name, 16) = %L',
      'OPERATOR_SCHEMA_'
    )
  LOOP
    RETURN QUERY EXECUTE
      format('SELECT id, %L AS schema_name FROM %I.children', quote_literal(schema.schema_name), schema.schema_name);
  END LOOP;
END;
$$ LANGUAGE plpgsql;

ERROR:  structure of query does not match function result type
DETAIL:  Returned type unknown does not match expected type character varying in column 2.
CONTEXT:  PL/pgSQL function all_children_dynamic() line 11 at RETURN QUERY

为什么返回类型未知?我预计它会插入一个字符串并返回该类型。

【问题讨论】:

  • 您得到的确切错误是什么?由于您要向查询中添加一个新列(在本例中为架构名称),因此函数结果不是 setof children 。正确的?因此,您可能需要查看here 中提到的返回表类型
  • @cableload 我添加了两个我一直在尝试的错误示例。请记住,我不知道自己在做什么 :)
  • 您可以根据错误看到,您无法返回 SETOF Children,因为您正在添加另一列。尝试返回您希望返回的所有列的表。你的 SQL 语法对我来说很好。
  • @cableload 越来越近了,但是当我尝试插入字符串时,它似乎没有识别返回类型。很抱歉打扰您,感谢您的帮助!
  • 你用 %L 替换 %s 有什么原因吗? %s 没用?尝试将其转换为 SELECT id, %L::varchar AS schema_name FROM %I.children 之类的 varchar

标签: sql database postgresql plpgsql dynamic-sql


【解决方案1】:

由于您要向查询添加新列(在本例中为架构名称),因此函数结果不是一组子项。因此,需要返回包含附加列的表类型。语法可见here。

像这样..

CREATE OR REPLACE FUNCTION all_children_dynamic() RETURNS 
TABLE(col1 col1type,col2 col2type,...., schema_name varchar) AS $$

第二个错误是由于不正确的转换为 postgres,因为版本 9 已经真正具体地针对返回数据类型。例如。如果您在函数返回类型中返回 varchar(8),则必须返回相同长度的 varchar。因此需要铸造。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-03
    • 1970-01-01
    • 2021-11-26
    • 2021-12-03
    • 2019-08-28
    • 2021-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多