0

我有一个表,其中包含数据库中其他表的索引。

之前我迭代了这个索引来执行queries on the tables indexed,,但正如您可能想象的那样,这对于大量表来说非常慢。

我想知道是否有可能从我的索引表上的查询结果形成一个表表达式,因此使用我的索引表上的查询的 FROM 将我的查询写成一条语句list of tables result

ETA:我正在使用 PostgreSQL v9.0。我通过一次迭代一个查询来查询具有相同查询的多个表(这很慢)。我想加快速度,如果有一种方法可以使用一个表表达式查询所有表,该表表达式是从索引表中选择的所有表的列表。

我的(简化的)表是“tabledata”,其中包含相同模式表 A、B、C、D、E、F、G 的列表以及每个表的布尔值“启用”。我想查询所有“启用”为真的字母表;最好使用一个查询,而不是一次遍历它们。基本上查询那些返回的表:

SELECT tablename FROM tabledata WHERE enabled = TRUE`

ETA2:我在查询工具中输入了以下内容:

CREATE FUNCTION f_all_tables()
  RETURNS SETOF A AS 
$body$
DECLARE 
    _tbl oid;
BEGIN 
FOR _tbl IN 
    SELECT tablename::regclass
    FROM   tabledata 
    WHERE  enabled 
LOOP 
    RETURN QUERY EXECUTE  '
    SELECT * FROM ' || _tbl; 
END LOOP; 
END;

$body$ language plpgsql; 

SELECT * FROM f_all_tables();

并得到一个错误:

ERROR:  invalid input syntax for type oid: "A"
CONTEXT:  PL/pgSQL function "f_all_tables" line 6 at FOR over SELECT rows

A的第一个表名在哪里tabledata

ETA3:

我已经实现了下面的第二个解决方案并且它有效。谢谢 示例代码:

CREATE TABLE tabledata2 
(
  tablename character(64) NOT NULL,
  enabled boolean
)
WITH (
  OIDS=FALSE
);
ALTER TABLE tabledata2
  OWNER TO postgres;

CREATE TABLE AAAAAA
(
  enabled boolean
)
WITH (
  OIDS=FALSE
);
ALTER TABLE AAAAAA
  OWNER TO postgres;
CREATE TABLE AAAAAB
(
  enabled boolean
)
WITH (
  OIDS=FALSE
);
ALTER TABLE AAAAAB
  OWNER TO postgres;

INSERT INTO tabledata2 VALUES ('AAAAAA', 'true');
INSERT INTO tabledata2 VALUES ('AAAAAB', 'true');
INSERT INTO AAAAAA VALUES ('true');
INSERT INTO AAAAAB VALUES ('false');

CREATE FUNCTION f_all_tables() 
  RETURNS SETOF AAAAAA AS  
$body$ 
DECLARE  
    _tbl regclass; 
BEGIN  
FOR _tbl IN  
    SELECT tablename::regclass 
    FROM   tabledata2  
    WHERE  enabled
LOOP  
    RETURN QUERY EXECUTE  ' 
    SELECT * FROM ' || _tbl;  
END LOOP;  
END; 

$body$ language plpgsql;  

SELECT * FROM f_all_tables(); 
4

2 回答 2

3

我从您的评论中得知,您所有的候选表都共享相同的布局。

您自己已经知道,正确的方法是拥有一个包含所有行的表,可能还有一个额外的列来标记它们的类型。

从一个表中检索行

CREATE FUNCTION f_table(int)
  RETURNS SETOF A AS
$body$
BEGIN

    RETURN QUERY EXECUTE '
    SELECT * FROM ' || tablename::regclass FROM mytables WHERE id = $1;

END;
$body$ language plpgsql;

称呼:

SELECT * FROM f_table(42);

要点:

  • 您可以像查询表一样查询“表函数”(函数返回SETOF值)。

  • 您的表共享相同的布局。因此,您可以定义返回类型,而不必在每次调用时都键入列定义列表。

  • 您必须知道 PostgreSQL 中的每个表都有一个同名的复合类型。这就是为什么您可以使用其中一个表的名称(A在我的示例中)作为返回类型并且它会起作用。

  • 我使用转换regclass为表名而不是quote_ident(tablename). 它也可以防止 SQL 注入,它也适用于模式限定的表名,例如myschma.mytable. quote_ident()将是一个好主意,但在这种情况下失败。

  • 永远无法定义具有动态 SQL 的函数STABLE更多关于在手册中创建函数的信息。


从所有表中检索行

(所有相同的基本类型。)
首先:纯 SQL无法使用动态表列表来执行此操作。

CREATE FUNCTION f_all_tables()
  RETURNS SETOF A AS
$body$
DECLARE
    _tbl regclass;
BEGIN

FOR _tbl IN
    SELECT tablename::regclass
    FROM   tabledata
    WHERE  enabled
LOOP
    RETURN QUERY EXECUTE '
    SELECT * FROM ' || _tbl;
END LOOP;

END;
$body$ language plpgsql;

称呼:

SELECT * FROM f_all_tables();

如果这组表的成员不会改变,你可以写一个丑陋的UNION SELECT

SELECT * FROM A
UNION ALL
SELECT * FROM B
...

UNION ALL保留结果中的所有重复项。

于 2012-04-13T13:03:27.907 回答
1

就像是:

SELECT * FROM (SELECT tablename FROM mytables WHERE id = 42);

? 那是不可能的。

最明显的方法是使用带有 EXECUTE 的动态语句。您可以编写一个函数,该函数采用表的名称并返回所有行的所有列,然后您需要为其指定列定义列表:

CREATE FUNCTION select_from_table(TEXT) RETURNS SETOF RECORD
STABLE LANGUAGE 'plpgsql' AS
$$
BEGIN
    RETURN QUERY EXECUTE 'SELECT * FROM ' || quote_ident($1);
END;
$$;

SELECT * FROM select_from_table('pg_namespace') AS s(nspname name, nspowner oid, nspacl aclitem[]);

你得想想这有多丑。如果您的所有表都将具有相同的架构,那么您可以通过返回正确的类型来稍微清理它(而不是让调用者每次都指定又大又丑的列定义列表)。

更好的是,如果您总是想以某种方式进行过滤,您可以这样做。

但一般来说,您还应该考虑您要完成的工作以及是否可以用更 SQL 的方式来完成。

于 2012-04-12T22:29:49.650 回答