【问题标题】:SELECT dynamic columns without functions in PostgreSQL在 PostgreSQL 中选择没有函数的动态列
【发布时间】:2011-12-24 13:04:12
【问题描述】:

我需要从两个或更多表(“A”、“B”)中选择行。他们有不同的列,我不使用继承。

所以。例如:

SELECT * FROM "A" UNION SELECT * FROM "B" 
ERROR: each UNION query must have the same number of columns

我能理解为什么。

我尝试从根表中的根模式获取相交列:

SELECT column_name FROM information_schema.columns
WHERE table_schema = 'client_root' AND table_name ='conditions'

没关系!但我不使用查询:

SELECT
   (SELECT column_name FROM information_schema.columns
    WHERE table_schema = 'client_root' AND table_name ='conditions')
FROM "client_123"."A"

所以。如何将子选择数据放入根选择中?

【问题讨论】:

  • 也许你对我说如何将表与动态结构联合起来?
  • 我不相信有办法做到这一点。您必须查询 information_schema.columns 以获取每个表的必要元数据。

标签: sql postgresql union plpgsql dynamic-sql


【解决方案1】:

您尝试做的事情几乎不可能全部完成。

创建动态 SQL

首先,您可以执行以下操作:为此类查询创建 SQL 的 plpgsql 函数:

CREATE OR REPLACE FUNCTION f_union_common_col_sql(text, text)
 RETURNS text
AS $function$
DECLARE 
  _cols text;
BEGIN

_cols := string_agg(attname, ', ')
FROM (
    SELECT a.attname
    FROM   pg_attribute a
    WHERE  a.attrelid = $1::regclass::oid
    AND    a.attnum >= 1
    INTERSECT
    SELECT a.attname
    FROM   pg_attribute a
    WHERE  a.attrelid = $2::regclass::oid
    AND    a.attnum >= 1
    ) x;

RETURN 'SELECT ' || _cols || '
FROM   ' || quote_ident($1) || '
UNION
SELECT ' || _cols || '
FROM   ' || quote_ident($1);

END;
$function$  LANGUAGE plpgsql;

COMMENT ON FUNCTION f_union_common_col_sql(text, text) IS 'Create SQL to query all visible columns that two tables have in common.
# Without duplicates. Use UNION ALL if you want to include duplicates.
# Depends on visibility dicatated by search_path
$1 .. table1: optionally schema-qualified, case sensitive!
$2 .. table2: optionally schema-qualified, case sensitive!';

呼叫:

SELECT f_union_common_col_sql('myschema1.tbl1', 'myschema2.tbl2');

为您提供完整的查询。在第二次调用中执行它。

您可以在manual on plpgsql functions 中找到我在这里使用的大部分内容。
aggregate function string_agg() 是在 PostgreSQL 9.0 中引入的。在旧版本中,您可以:array_to_string(array_agg(attname), ', ')


执行动态 SQL?

接下来,这是你几乎不能做的事情:

CREATE OR REPLACE FUNCTION f_union_common_col(text, text)
  RETURNS SETOF record AS
$BODY$
DECLARE 
  _cols text;
BEGIN

_cols := string_agg(attname, ', ')
FROM (
    SELECT a.attname
    FROM   pg_attribute a
    WHERE  a.attrelid = $1::regclass::oid
    AND    a.attnum >= 1
    INTERSECT
    SELECT a.attname
    FROM   pg_attribute a
    WHERE  a.attrelid = $2::regclass::oid
    AND    a.attnum >= 1
    ) x;

RETURN QUERY EXECUTE '
SELECT ' || _cols || '
FROM quote_ident($1)
UNION
SELECT ' || _cols || '
FROM quote_ident($2)';

END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

COMMENT ON FUNCTION f_union_common_col(text, text) IS 'Query all visible columns that two tables have in common.
# Without duplicates. Use UNION ALL if you want to include duplicates.
# Depends on visibility dicatated by search_path
# !BUT! you need to specify a column definition list for every call. So, hardly useful.
$1 .. table1 (optionally schema-qualified)
$2 .. table1 (optionally schema-qualified)';

函数调用要求您指定目标列的列表。所以这根本没用:

SELECT * from f_union_common_col('myschema1.tbl1', 'myschema2.tbl2')

ERROR:  a column definition list is required for functions returning "record"

没有简单的方法可以解决这个问题。您必须动态创建一个函数或至少一个复杂类型。这是我停下来的地方。

【讨论】:

  • 我在没有创建新函数的情况下询问了请求
  • @Arturgspb:这在普通 SQL 中通常是不可能的。对于涉及动态确定标识符的查询,您必须使用函数或 anonymous code block (DO statement)
  • 有大量申诉会大大减慢。
  • 所以使用两个查询。首先查询目录以获取我在第一个函数中演示的文件(可以使用普通 SQL 完成),构建实际查询并执行它。额外的步骤需要几毫秒。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-22
  • 1970-01-01
相关资源
最近更新 更多