我有一个带有rails的mysql数据库,还有一个“简写”(字符串)列,我想在多个表中使其独一无二。有没有办法在不制作第三张桌子的情况下做到这一点?
Expression
id
shorthand
...
etc
Variable
id
shorthand
...
etc
我希望两个表的'速记'列中的值在彼此之间是唯一的,即。如果已经在DB中存在具有速记值“xyz”的变量,则表达式中的记录速记值“xyz”将被拒绝。
任何想法都赞赏,甚至“你必须使用第三张桌子”:)
答案 0 :(得分:0)
我认为这篇较旧的文章完全符合您的要求(模拟多表约束): http://classes.soe.ucsc.edu/cmps180/Winter04/constraints.html
您可能还想使用与文章中的CREATE CONSTRAINT TRIGGER
功能类似的功能调查postgres check_nojoin()
。
http://www.postgresql.org/docs/9.0/static/sql-createconstraint.html
获得所需的确切SQL后,可以使用execute "the required SQL"
另一种方法是使用第三个表'短号'用列'简写'和' src'。将速记定义为该表上的唯一主键。在其他两个表格的每一个上定义“src'作为一个单一的char字段默认为' A'和' B'在每张桌子上分别。在两个表中的每一个表上添加一个外键约束,包括'简写'和' src'并引用表'短号'。在两个表中的任何一个表中插入或更新行时,您需要确保'缩写'表格作为交易的一部分或通过触发器明确更新,并设置'简写'和' src'到相应的表格即“A'或者' B'。
外键约束的作用是确保速记值存在于相应src表的速记表中,但由于仅对“ ”速记'的唯一性约束。如果另一个表已经定义了速记值,那么速记表中的列将发生密钥违规,从而保证两个(甚至更多)表的唯一性。
无论您做什么,最好将参照完整性放入数据库,而不是在orm / active记录验证中。
答案 1 :(得分:0)
这是一个使用第三个表的例子:
-- TEMP SCHEMA for testing
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;
CREATE TABLE shorthand
( shorthand varchar NOT NULL PRIMARY KEY
, one_or_two varchar NOT NULL
);
CREATE TABLE table_one
( one_id INTEGER NOT NULL PRIMARY KEY
, shorthand varchar NOT NULL REFERENCES shorthand(shorthand)
ON DELETE CASCADE ON UPDATE CASCADE
DEFERRABLE INITIALLY DEFERRED
, etc_one varchar
);
CREATE TABLE table_two
( two_id INTEGER NOT NULL PRIMARY KEY
, shorthand varchar NOT NULL REFERENCES shorthand(shorthand)
ON DELETE CASCADE ON UPDATE CASCADE
DEFERRABLE INITIALLY DEFERRED
, etc_two varchar
);
-- Trigger function for BOTH tables
CREATE FUNCTION set_one_or_two( ) RETURNS TRIGGER
AS $func$
BEGIN
IF (TG_OP = 'INSERT') THEN
INSERT INTO shorthand (shorthand, one_or_two)
VALUES(new.shorthand, TG_TABLE_NAME)
;
ELSEIF (TG_OP = 'UPDATE') THEN
UPDATE shorthand SET shorthand = new.shorthand
WHERE shorthand = old.shorthand
;
ELSEIF (TG_OP = 'DELETE') THEN
DELETE FROM shorthand
WHERE shorthand = old.shorthand
;
END IF;
RETURN NULL;
END
$func$ LANGUAGE plpgsql
;
-- Triggers for I/U/D
CREATE CONSTRAINT TRIGGER check_one
AFTER INSERT OR UPDATE OR DELETE
ON table_one
FOR EACH ROW
EXECUTE PROCEDURE set_one_or_two ( )
;
CREATE CONSTRAINT TRIGGER check_two
AFTER INSERT OR UPDATE OR DELETE
ON table_two
FOR EACH ROW
EXECUTE PROCEDURE set_one_or_two ( )
;
-- Some tests (incomplete)
INSERT INTO table_one (one_id,shorthand,etc_one) VALUES (1, 'one' , 'one' );
INSERT INTO table_two (two_id,shorthand,etc_two) VALUES (1, 'two' , 'two' );
SELECT * FROM shorthand;
\echo this should fail
INSERT INTO table_one (one_id,shorthand,etc_one) VALUES (11, 'two' , 'eleven' );
SELECT * FROM shorthand;
UPDATE table_one SET shorthand = 'eleven' WHERE one_id = 1;
SELECT * FROM shorthand;