将架构名称添加到动态 Postgres 查询
Add schema name to dynamic Postgres query
我的数据库使用 Postgres 架构为用户提供一个单独的 multi-tenant 环境。每个模式都有相同表的副本。
我有一个特定的查询,我需要跨模式加入,return 记录列表(在本例中,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();
这 return 类似于:
-------------
| id | name |
| 1 | Bob |
| 2 | Joe |
-------------
而我希望它 return 类似于:
-------------------------------
| id | name | schema_name |
| 1 | Bob | darcy's-store |
| 2 | Joe | bob's-4th-store |
-------------------------------
需要注意的是,模式名称是用户定义的,可以包含引号。
如何为每个 child 添加相关的架构名称?
我尝试了以下几种变体:
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
为什么返回的 return 类型未知?我预计它会插入一个字符串,然后 returning 该类型。
由于您要向查询中添加一个新列(在本例中为架构名称),因此函数结果不是一组子项。因此,table 类型需要 returned 并包含其中的附加列。语法可见 here 。
像这样..
CREATE OR REPLACE FUNCTION all_children_dynamic() RETURNS
TABLE(col1 col1type,col2 col2type,...., schema_name varchar) AS $$
第二个错误是由于 postgres 转换不当造成的,因为第 9 版对 return 数据类型非常具体。例如。如果您在函数 return 类型中 returning varchar(8),则必须 return 相同长度的 varchar。因此需要铸造。
我的数据库使用 Postgres 架构为用户提供一个单独的 multi-tenant 环境。每个模式都有相同表的副本。
我有一个特定的查询,我需要跨模式加入,return 记录列表(在本例中,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();
这 return 类似于:
-------------
| id | name |
| 1 | Bob |
| 2 | Joe |
-------------
而我希望它 return 类似于:
-------------------------------
| id | name | schema_name |
| 1 | Bob | darcy's-store |
| 2 | Joe | bob's-4th-store |
-------------------------------
需要注意的是,模式名称是用户定义的,可以包含引号。
如何为每个 child 添加相关的架构名称?
我尝试了以下几种变体:
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
为什么返回的 return 类型未知?我预计它会插入一个字符串,然后 returning 该类型。
由于您要向查询中添加一个新列(在本例中为架构名称),因此函数结果不是一组子项。因此,table 类型需要 returned 并包含其中的附加列。语法可见 here 。
像这样..
CREATE OR REPLACE FUNCTION all_children_dynamic() RETURNS
TABLE(col1 col1type,col2 col2type,...., schema_name varchar) AS $$
第二个错误是由于 postgres 转换不当造成的,因为第 9 版对 return 数据类型非常具体。例如。如果您在函数 return 类型中 returning varchar(8),则必须 return 相同长度的 varchar。因此需要铸造。