有一个表t继承了孩子。我希望只有孩子才能收到插页。强制父表拒绝插入的最佳方法是什么?
create table t (c int);
create table t1 () inherits (t);
这不应该是可能的:
insert into t (c) values (1);
编辑:
除了@wildplasser:
之外,我找到了一个模型可见的解决方案create table tfk (c integer unique check(false));
create table t (c integer, foreign key (c) references tfk(c));
现在不可能insert into t
除非它是空值,并且仍然可以insert into
其子项。如果该列已经被约束为not null
,那么它可以是一个很好的解决方案,否则就不够了。或者有人知道如何使上述工作为空值吗?
我在postgresql列表中asked for a new syntax,它已经完成了9.2:
允许CHECK约束被声明为NO INHERIT(Nikhil Sontakke,Alex Hunsaker)
这使得它们只能在父表上强制执行,而不能在子表上强制执行。
答案 0 :(得分:5)
create table t (c int, check (false) no inherit);
这将阻止插入表t
。它添加了一个永远不会成立的约束,因此不能插入任何数据。 no inherit
将阻止该约束影响子表。
答案 1 :(得分:3)
您可以使用before insert触发器引发错误或重定向到正确的表。
答案 2 :(得分:1)
这很难看,但似乎有效:
--SET search_path='tmp';
DROP TABLE dontinsert CASCADE;
CREATE TABLE dontinsert
( id INTEGER NOT NULL PRIMARY KEY
);
DROP TABLE doinsert CASCADE;
CREATE TABLE doinsert ()
INHERITS (dontinsert)
;
CREATE RULE dont_do_it AS
ON INSERT TO dontinsert
DO INSTEAD NOTHING
;
INSERT INTO dontinsert(id) VALUES( 13) ;
INSERT INTO doinsert(id) VALUES( 42) ;
SELECT id AS id_from_dont FROM dontinsert;
SELECT id AS id_from_do FROM doinsert;
结果:
SET
NOTICE: drop cascades to table doinsert
DROP TABLE
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "dontinsert_pkey" for table "dontinsert"
CREATE TABLE
ERROR: table "doinsert" does not exist
CREATE TABLE
CREATE RULE
INSERT 0 0
INSERT 0 1
id_from_dont
--------------
42
(1 row)
id_from_do
------------
42
(1 row)
更新:由于OP希望INSERTS失败并带来很多噪音,我不得不添加一个带有不可能约束的金丝雀表:
DROP TABLE alwaysempty CASCADE;
CREATE TABLE alwaysempty
( id INTEGER NOT NULL
);
ALTER TABLE alwaysempty
ADD CONSTRAINT dont_insert_you_sucker CHECK (id > 0 AND id < 0)
;
CREATE RULE dont_do_it AS
ON INSERT TO dontinsert
DO INSTEAD -- NOTHING
INSERT INTO alwaysempty (id)
VALUES (NEW.id)
;
新输出:
SET
NOTICE: drop cascades to table doinsert
DROP TABLE
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "dontinsert_pkey" for table "dontinsert"
CREATE TABLE
ERROR: table "doinsert" does not exist
CREATE TABLE
DROP TABLE
CREATE TABLE
ALTER TABLE
CREATE RULE
ERROR: new row for relation "alwaysempty" violates check constraint "dont_insert_you_sucker"
INSERT 0 1
id_from_dont
--------------
42
(1 row)
id_from_do
------------
42
(1 row)
下一次尝试:将基本表格(仅限)移动到不可缓存的模式中(因为我真的讨厌触发器)......
SET search_path='tmp';
DROP SCHEMA hidden CASCADE;
CREATE SCHEMA hidden;
REVOKE ALL ON SCHEMA hidden FROM PUBLIC;
DROP TABLE dontinsert CASCADE;
CREATE TABLE dontinsert
( id INTEGER NOT NULL PRIMARY KEY
);
DROP TABLE doinsert CASCADE;
CREATE TABLE doinsert ()
INHERITS (dontinsert)
;
ALTER TABLE ONLY dontinsert SET SCHEMA hidden;
INSERT INTO alwaysempty (id) VALUES (NEW.id) ;
INSERT INTO dontinsert(id) VALUES( 13) ;
INSERT INTO doinsert(id) VALUES( 42) ;
SELECT id AS id_from_dont FROM hidden.dontinsert;
SELECT id AS id_from_do FROM doinsert;
答案 3 :(得分:0)
更新: revoke update
等实际上很糟糕,因为它会使更新失败并且不会将它们自动导向分区 :-(
...所以最佳方式对我来说似乎是@JoeVanDyk s simple always-false check condition 。
作为 @derobert 在评论中已经提到过,对我来说似乎很好,考虑开销,速度和实用性,这样做通过权利:
revoke insert, update, references on my_master_table from my_upd_usr
(references
因为如果使用它就不会按预期工作:inheritance caveats)
(当然,让一些用户有权在意外中插入到主人身上似乎是可能的,例如通过给予所有表格的权利,但我想它通常不太可能给某人&#34 ;意外地&#34; DML操作的权利。 即使这个人拥有权利,为什么他应该开始插入一个空表,看到它没有以这种方式使用,数据驻留在分区中。)