我的数据库被分成基于客户端的模式(即:每个客户端都有自己的模式,具有相同的数据结构)。
我也碰巧有一个外部动作,不知道它应该针对哪个架构。它来自系统的另一部分,它没有客户端的概念,也不知道它在哪个客户端设置中运行。在我处理它之前,我必须找出请求需要定位的模式
要找到正确的架构,我必须找出哪个包含特定唯一ID(字符串)的记录R
据我了解,以下
SET search_path TO schema1,schema2,schema3,...
只会查看schema1中的表(或与表匹配的第一个模式),并且不会进行全局搜索。
我有没有办法在所有模式中进行全局搜索,或者我只需要使用for循环并迭代所有模式,一次一个?
答案 0 :(得分:5)
您可以使用inheritance。 (请务必考虑limitations。)
考虑一下这个小小的演示:
CREATE SCHEMA master; -- no access of others ..
CREATE SEQUENCE master.myseq; -- global sequence to have globally unique id
CREATE table master.tbl (
id int primary key DEFAULT nextval('master.myseq')
, foo text);
CREATE SCHEMA x;
CREATE table x.tbl() INHERITS (master.tbl);
INSERT INTO x.tbl(foo) VALUES ('x');
CREATE SCHEMA y;
CREATE table y.tbl() INHERITS (master.tbl);
INSERT INTO y.tbl(foo) VALUES ('y');
SELECT * FROM x.tbl; -- returns 'x'
SELECT * FROM y.tbl; -- returns 'y'
SELECT * FROM master.tbl; -- returns 'x' and 'y' <-- !!
-- clean it all up:
-- DROP SCHEMA x, y, master CASCADE;
现在,要实际识别特定行所在的表格,请使用tableoid
:
SELECT *, tableoid::regclass AS table_name
FROM master.tbl
WHERE id = 2;
结果:
id | foo | table_name
---+-----+-----------
2 | y | y.tbl
您可以从tableoid
派生源架构,最好直接使用tableoid
查询系统目录。 (显示的名称取决于search_path
的设置。)
SELECT n.nspname
FROM master.tbl t
JOIN pg_class c ON c.oid = t.tableoid
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE t.id = 2;
这也比循环遍历许多单独的表更快 。
答案 1 :(得分:1)
您必须遍历所有名称空间。您可以从pg_*
系统目录中获取大量此类信息。从理论上讲,您应该能够解析客户端 - &gt;请求时的模式映射,而不与数据库通信,因此您进行的第一个SQL调用是:
SET search_path = client1,global_schema;
答案 2 :(得分:1)
虽然我认为如果您可以重新构建表,Erwin的解决方案可能更好,但是不需要任何模式更改的替代方法是编写PL / PgSQL函数,该函数使用基于系统目录的动态SQL扫描表信息。
假设:
CREATE SCHEMA a;
CREATE SCHEMA b;
CREATE TABLE a.testtab ( searchval text );
CREATE TABLE b.testtab (LIKE a.testtab);
INSERT INTO a.testtab(searchval) VALUES ('ham');
INSERT INTO b.testtab(searchval) VALUES ('eggs');
以下PL / PgSQL函数搜索包含名为_tabname
的表的所有模式,以查找_colname
中等于_value
的值,并返回第一个匹配模式。
CREATE OR REPLACE FUNCTION find_schema_for_value(_tabname text, _colname text, _value text) RETURNS text AS $$
DECLARE
cur_schema text;
foundval integer;
BEGIN
FOR cur_schema IN
SELECT nspname
FROM pg_class c
INNER JOIN pg_namespace n ON (c.relnamespace = n.oid)
WHERE c.relname = _tabname AND c.relkind = 'r'
LOOP
EXECUTE
format('SELECT 1 FROM %I.%I WHERE %I = $1',
cur_schema, _tabname, _colname
) INTO foundval USING _value;
IF foundval = 1 THEN
RETURN cur_schema;
END IF;
END LOOP;
RETURN NULL;
END;
$$ LANGUAGE 'plpgsql';
如果没有匹配则返回null。如果有多个匹配,则结果将是其中之一,但不保证哪一个匹配。如果要按字母顺序返回(比方说)第一个,请在架构查询中添加ORDER BY
子句。如果您想要返回所有匹配项,该函数也会被轻微修改为返回setof text
和RETURN NEXT cur_schema
。
regress=# SELECT find_schema_for_value('testtab','searchval','ham');
find_schema_for_value
-----------------------
a
(1 row)
regress=# SELECT find_schema_for_value('testtab','searchval','eggs');
find_schema_for_value
-----------------------
b
(1 row)
regress=# SELECT find_schema_for_value('testtab','searchval','bones');
find_schema_for_value
-----------------------
(1 row)
顺便说一句,如果你愿意的话,你可以重新使用表定义而不继承,你真的应该这样做。使用通用的复合数据类型:
CREATE TYPE public.testtab AS ( searchval text );
CREATE TABLE a.testtab OF public.testtab;
CREATE TABLE b.testtab OF public.testtab;
在这种情况下,它们共享相同的数据类型,但不共享任何数据;或通过LIKE
:
CREATE TABLE public.testtab ( searchval text );
CREATE TABLE a.testtab (LIKE public.testtab);
CREATE TABLE b.testtab (LIKE public.testtab);
在这种情况下,他们在创建后完全没有连接。