1

皆さん、私が現在答えようとしている大きな問題があります: 「自分で 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テーブルをインターセプトし、実際に保存されている電話番号の種類を特定しますそうでない場合は、HomePhoneNumberインスタンスであると確信しています。同じことがCellPhoneNumberインスタンスにも当てはまります。

問題は、INSERT INTO TelephoneNumber VALUES(DEFAULT, '39', 'N/A', '010', '7708124');HomePhoneNumber インスタンスであることがわかっている I の場合、Postgres が int から enum にキャストできないと不平を言い、値 '39' (イタリアの国際接頭語、BTW) を指していることです。たとえば、プレフィックス列のタイプをテキストに変更すると、Postgres は最終的に文句を言わなくなりますが、値はトリガーの効果として「親」 TelephoneNumberテーブルにのみ正しく格納されますが、「派生」 HomePhoneNumberテーブルには格納されません。これは、EXECUTE ステートメントがまったく効果がないことを示唆しています。だから、私の本当の質問は次のとおりです。

  1. これらの値を EXECUTE ステートメントで列挙値に変換できないのはなぜですか? (私はそれをどういうわけか間違っているのではないかと心配しています)
  2. プレフィックス列のタイプをテキストに変更しても、子テーブルへの伝播が効果がないのはなぜですか?

int 値を enum 値にキャストしようとしたときに発生する正確なエラーは次のとおりです。

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 ステートメントで enum 値をキャストしようとしましたが、うまくいきませんでした。35時なので助かります。私は目を覚ましてpgAdmin IIIと戦っています... D:

PS: 階層全体で参照整合性を保証するために、さらに関数とトリガーを作成する必要があることはわかっています。上記は、どのルートを取るべきかを理解するための単なるサンプルです。みなさん、よろしくお願いします!

4

1 に答える 1

2

これらの値を EXECUTE ステートメントで列挙値に変換できないのはなぜですか?

列挙値は常に文字リテラルです (一重引用符で囲む必要があります)。

したがって、次のようなことをする必要があります。

EXECUTE 'INSERT INTO HomePhoneNumber VALUES(' 
         || NEW.telephoneNumber_ID 
         || ', ''' || NEW.countryCode || ''', ' 
         || NEW.townPrefix || ', ' || NEW.coreNumber|| ');' USING NEW;

「国コード」を文字リテラルにするために、式内に一重引用符が追加されていることに注意してください。

于 2012-11-26T13:32:42.513 に答える