在PostgreSQL中没有函数的SELECT动态列

时间:2022-11-15 22:58:09

I need to select rows from two and more tables ("A", "B"). They have differences columns and I don't use inheritance for it.

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

So. For example:

所以。例如:

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

I can understand why.

我明白为什么。

I try get intersected columns from root schema in root table:

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

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

It's ok! But I don't use query:

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

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

So. How I can put sub select data in root select?

所以。如何在root选择中放置子选择数据?

1 个解决方案

#1


2  

What you are trying to do is hardly possible in its entirety.

您要做的事情几乎不可能完全实现。

Create dynamic SQL

First, here is what you can do: a plpgsql function that creates the SQL for such a query:

首先,您可以执行以下操作:为这样的查询创建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!';

Call:

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

Gives you the complete query. Execute it in a second call.

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

You can find most everything I used here in the manual on plpgsql functions.
The aggregate function string_agg() was introduced with PostgreSQL 9.0. In older versions you would: array_to_string(array_agg(attname), ', ').

你可以在plpgsql函数的手册中找到我在这里使用的大部分内容。 PostgreSQL 9.0引入了聚合函数string_agg()。在旧版本中,您将:array_to_string(array_agg(attname),',')。


Execute dynamic SQL?

Next, here is what you hardly can do:

接下来,这是你几乎无法做到的事情:

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)';

A function call requires you to specify the list of target columns. so this is hardly useful at all:

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

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

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

There is no easy way around this. You would have to dynamically create a function or at least a complex type. This is where I stop.

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

#1


2  

What you are trying to do is hardly possible in its entirety.

您要做的事情几乎不可能完全实现。

Create dynamic SQL

First, here is what you can do: a plpgsql function that creates the SQL for such a query:

首先,您可以执行以下操作:为这样的查询创建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!';

Call:

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

Gives you the complete query. Execute it in a second call.

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

You can find most everything I used here in the manual on plpgsql functions.
The aggregate function string_agg() was introduced with PostgreSQL 9.0. In older versions you would: array_to_string(array_agg(attname), ', ').

你可以在plpgsql函数的手册中找到我在这里使用的大部分内容。 PostgreSQL 9.0引入了聚合函数string_agg()。在旧版本中,您将:array_to_string(array_agg(attname),',')。


Execute dynamic SQL?

Next, here is what you hardly can do:

接下来,这是你几乎无法做到的事情:

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)';

A function call requires you to specify the list of target columns. so this is hardly useful at all:

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

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

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

There is no easy way around this. You would have to dynamically create a function or at least a complex type. This is where I stop.

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