根据表值找出哪个模式
Posted
技术标签:
【中文标题】根据表值找出哪个模式【英文标题】:Find out which schema based on table values 【发布时间】:2012-10-05 19:22:55 【问题描述】:我的数据库根据客户端分为多个模式(即:每个客户端都有自己的模式,具有相同的数据结构)。
我也碰巧有一个不知道它应该针对哪个架构的外部操作。它来自系统的另一部分,它没有客户的概念,也不知道它在哪个客户的集合中运行。在处理它之前,我必须找出该请求需要针对哪个架构
要找到正确的架构,我必须找出哪个记录 R
具有特定的唯一 ID(字符串)
据我了解,如下
SET search_path TO schema1,schema2,schema3,...
只会查看 schema1 中的表(或与表匹配的第一个模式),不会进行全局搜索。
有没有办法让我在所有模式中进行全局搜索,还是我只需要使用 for 循环并一次一个地遍历所有模式?
【问题讨论】:
据我了解,您想要做的是通过多个模型搜索您输入的字符串?就像假设用户输入“你好”一样,您希望在让我们说模型中搜索这个你好:汽车、公共汽车、自行车。我理解你的问题吗? @Jonathanq:不,每个模式都是相同的,我想在同一个模型中查找数据,只是跨越不同的模式:所以 schema1.cars、schema2.cars、schema3.cars 等。 【参考方案1】:您可以为此使用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;
这也比遍历许多单独的表快很多。
【讨论】:
听起来很复杂。 django 处理 PostgreSQL 继承的能力如何? 我不是 Django 专家,但这一点也不复杂。事实上,如果您在许多模式中都有相同的表,它会大大简化CREATE
脚本。需要明确的是:所有 CREATE 命令都必须只执行一次。但无论如何,这很清楚,对吧?忘记加的8现在加了):如何识别源表。【参考方案2】:
虽然我认为 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);
在这种情况下,它们在创建后彼此完全断开。
【讨论】:
【参考方案3】:您必须遍历所有命名空间。您可以从pg_*
系统目录中获得大量此类信息。理论上,您应该能够在请求时解析客户端 -> 架构映射,而无需与数据库对话,因此您进行的第一个 SQL 调用是:
SET search_path = client1,global_schema;
【讨论】:
以上是关于根据表值找出哪个模式的主要内容,如果未能解决你的问题,请参考以下文章
如何找出哪个进程正在侦听 Windows 上的 TCP 或 UDP 端口?