【发布时间】:2015-05-03 13:17:56
【问题描述】:
我有一个分区表(称为 A),其串行主键由另一个表(称为 B)引用。我知道我不能实际上创建一个从一个到另一个的外键(因为我不知道数据实际存储在哪个分区),所以相反,我试图模仿使用检查约束的外键行为。类似于以下内容:
CREATE TABLE A (
MyKey SERIAL PRIMARY KEY
);
CREATE TABLE B (
AKey INT, -- Should have: REFERENCES A (MyKey),
-- but can't due to Postgres limitations
);
CREATE TABLE APart1 (
Field1 INT,
PRIMARY KEY (MyKey)
) INHERITS (A);
CREATE TABLE APart2 (
Field2 INT,
PRIMARY KEY (MyKey)
) INHERITS (A);
CREATE FUNCTION ValidateKeyInA(aKey INT) RETURNS BOOL AS $$
BEGIN
PERFORM * FROM A WHERE MyKey = aKey;
IF FOUND THEN
RETURN TRUE;
END IF;
RETURN FALSE;
END;
$$ LANGUAGE PLPGSQL;
ALTER TABLE B ADD CHECK (ValidateKeyInA(AKey));
WITH aKey AS (INSERT INTO APart1 (Field1) VALUES (1) RETURNING MyKey)
INSERT INTO B (AKey) SELECT * FROM aKey;
WITH aKey AS (INSERT INTO APart2 (Field2) VALUES (2) RETURNING MyKey)
INSERT INTO B (AKey) SELECT * FROM aKey;
这工作得很好,直到我转储并恢复数据库。那时,Postgres 不知道表 B 依赖于表 A(及其分区)中的数据,而 B 恰好在表 A 之前被转储。我尝试将“DEFERRABLE”关键字添加到我所在的行添加约束,但 Postgres 不支持可延迟检查约束。
我建议的方法是将我的检查约束转换为一个约束触发器,我可以推迟它,然后在事务中导入我的数据库转储。有没有更直接的方法来解决这个问题?例如,有什么方法可以告诉 Postgres 在表 A 及其所有分区都被转储之前不要转储表 B(例如,将 B 的依赖项添加到 A 的分区)?我应该改用其他一些模式?谢谢。
【问题讨论】:
-
我不明白你是如何实现表分区的。哪一张是主桌?为什么不使用继承?顺便说一句,您的检查功能可能会更简单:
CREATE FUNCTION ValidateKeyInA(aKey INT) RETURNS BOOL AS $$ SELECT count(*) > 0 FROM A WHERE Key = aKey; $$ LANGUAGE sql; -
@TommasoDiBucchianico 我编辑了我的问题以明确显示我如何创建 A 的分区。我不知道在 PLPGSQL 函数中编写单个 select 语句会隐式返回结果。感谢您的建议(我几乎每次访问 SO 页面时都会学到一些新东西)。
-
只有 sql 函数隐式返回查询结果。我的函数是 sql 语言,不是 plpgsql
-
pg_dump 按字母顺序转储表,因此实际上表 A 在表 B 之前转储。在您的示例中,转储中的顺序应为:A、Apart1、Apart2、B。您能命名您的表吗以便字母顺序与“功能”顺序相对应?
-
@TommasoDiBucchianico 你能引用你的来源吗?我找到了this thread,这表明不仅顺序不是字母顺序,而且实际上是不确定的(参考 Postgres v8.4.2)。我查看了 9.3 here 的 pg_dump 文档,也找不到保证任何顺序的地方。
标签: postgresql foreign-keys postgresql-9.3 database-partitioning