[英]How to implement (or simulate) subtype polymorphism in PostgreSQL 9.2?
伙计们,我目前正试图回答一个大问题:“如何自己在 PostgreSQL 中实现(或至少模拟)子类型多态性”,因为我意识到 PostgreSQL 对继承的支持有些未定义。 到目前为止,尽可能简单明了,这是我的方法:
CREATE TABLE TelephoneNumber (
ID serial PRIMARY KEY,
countryCode CountryCodes_e NOT NULL,
operatorPrefix OperatorPrefixes_e,
townPrefix TownPrefixes_e,
coreNumber text NOT NULL
);
CREATE TABLE CellPhoneNumber (
cellPhoneNumber_ID serial PRIMARY KEY,
countryCode CountryCodes_e,
operatorPrefix OperatorPrefixes_e,
coreNumber text NOT NULL
);
CREATE TABLE HomePhoneNumber (
homePhoneNumber_ID serial PRIMARY KEY,
countryCode CountryCodes_e,
townPrefix TownPrefixes_e,
coreNumber text NOT NULL
);
.
.
.
TABLE Operation (
...
dateAndTime timestamp,
receiverPhoneNumber int8 REFERENCES TelephoneNumber
...
);
是的,我知道这个解决方案看起来很糟糕,因为我将相同的信息复制到不同的表中,但这就是重点:我在整个表层次结构中实现一致性模拟子表的属性继承(因为 PostgreSQL 不会让我将父表TelephoneNumber引用到外部Operation表中)。 我想要做的是在父表中插入一行,然后将该行传播到正确的CellPhoneNumber或HomePhoneNumber子表中。 (请注意,在我的情况下,子表的行数(每个 1)比它们的父表少)。
接下来,我写了一个触发函数:
CREATE OR REPLACE FUNCTION insertTelephoneNumberIntoProperTable_FNC() RETURNS TRIGGER AS $$
BEGIN
IF (NEW.operatorPrefix = 'N/A' AND NEW.townPrefix <> 'N/A') THEN
EXECUTE 'INSERT INTO HomePhoneNumber VALUES(' || NEW.telephoneNumber_ID || ', ' || NEW.countryCode::CountryCodes_e || ', ' || NEW.townPrefix || ', ' || NEW.coreNumber|| ');' USING NEW;
RETURN NEW;
ELSE
IF (NEW.operatorPrefix <> 'N/A' AND NEW.townPrefix = 'N/A') THEN
EXECUTE 'INSERT INTO CellPhoneNumber VALUES(' || NEW.telephoneNumber_ID || ', ' || NEW.countryCode::CountryCodes_e || ', ' || NEW.operatorPrefix || ', ' || NEW.coreNumber|| ');' USING NEW;
RETURN NEW;
END IF;
END IF;
RAISE EXCEPTION 'ERROR: Row is not valid!';
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER insertTelephoneNumberIntoProperTable_TRG
BEFORE INSERT ON TelephoneNumber
FOR EACH ROW
EXECUTE PROCEDURE insertTelephoneNumberIntoProperTable_FNC();
这将拦截 INSERTs INTO TelephoneNumber表并确定实际存储的电话号码类型:如果operatorPrefix等于 'N/A'(这是存储在 'OperatorPrefixes_e' 和 'TownPrefixes_e' 枚举中的特殊值)和townPrefix不是,那么我确定它是HomePhoneNumber实例。 这同样适用于CellPhoneNumber实例。
问题是,当我INSERT INTO TelephoneNumber VALUES(DEFAULT, '39', 'N/A', '010', '7708124');
,我们都知道它是一个 HomePhoneNumber 实例,Postgres 抱怨它不能从 int 转换为 enum,指向值 '39'(意大利国际前缀,顺便说一句)。 如果我将前缀列的类型更改为文本 Postgres 最终将不再抱怨,但值仅作为触发器的效果正确存储到“父” TelephoneNumber表中,而不是“派生” HomePhoneNumber表中,这表明我的 EXECUTE 语句根本没有效果。 所以,我真正的问题是:
尝试将 int 值转换为枚举值时得到的确切错误是:
ERROR: column "countrycode" is of type countrycodes_e but expression is of type integer
LINE 1: INSERT INTO HomePhoneNumber VALUES(1, 39, 010, 7708124);
^
HINT: You will need to rewrite or cast the expression.
QUERY: INSERT INTO HomePhoneNumber VALUES(1, 39, 010, 7708124);
CONTEXT: PL/pgSQL function inserttelephonenumberintopropertable_fnc() line 4 at EXECUTE statement
如您所见,我尝试在 EXECUTE 语句中强制转换枚举值,但没有成功。 希望你能帮助我,因为现在是 35 小时。 我醒着与 pgAdmin III 战斗... D:
PS:我知道我必须编写更多的函数和触发器,以保证整个层次结构中的引用完整性; 上面的只是一个示例,以便了解要走哪条路线。 提前谢谢大家!
枚举值始终是字符文字(需要用单引号括起来)。
所以你需要做这样的事情:
EXECUTE 'INSERT INTO HomePhoneNumber VALUES('
|| NEW.telephoneNumber_ID
|| ', ''' || NEW.countryCode || ''', '
|| NEW.townPrefix || ', ' || NEW.coreNumber|| ');' USING NEW;
请注意表达式中添加的单引号使“国家/地区代码”成为字符文字。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.