繁体   English   中英

如何在 PostgreSQL 9.2 中实现(或模拟)子类型多态?

[英]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表中)。 我想要做的是在父表中插入一行,然后将该行传播到正确的CellPhoneNumberHomePhoneNumber子表中。 (请注意,在我的情况下,子表的行数(每个 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 语句根本没有效果。 所以,我真正的问题是:

  1. 为什么我不能在 EXECUTE 语句中将这些值转换为枚举值? (我担心我做错了)
  2. 为什么,即使将前缀列的类型更改为文本,对子表的传播也没有效果?

尝试将 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM