_CREATE TABLE IF NOT EXISTS b2c_constants (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(64) NOT NULL,
is_deleted BOOL DEFAULT FALSE,
UNIQUE (name)
) ENGINE InnoDB CHARSET utf8 COLLATE utf8_unicode_ci
CREATE TABLE IF NOT EXISTS b2c_constant_bindings (
constant_id INT UNSIGNED NOT NULL,
company_id INT UNSIGNED NOT NULL,
object_id INT UNSIGNED DEFAULT NULL,
property_id INT UNSIGNED DEFAULT NULL,
value VARCHAR(255) NOT NULL,
UNIQUE (constant_id, company_id, object_id, property_id),
FOREIGN KEY (constant_id) REFERENCES b2c_constants (id) ON UPDATE RESTRICT ON DELETE CASCADE,
FOREIGN KEY (company_id) REFERENCES companies (id) ON UPDATE RESTRICT ON DELETE CASCADE,
FOREIGN KEY (object_id) REFERENCES b2b_objects (id) ON UPDATE RESTRICT ON DELETE CASCADE,
FOREIGN KEY (property_id) REFERENCES b2b_properties (id) ON UPDATE RESTRICT ON DELETE CASCADE
) ENGINE InnoDB CHARSET utf8 COLLATE utf8_unicode_ci
_
問題は、bindings
テーブルの一意のキーにあります。私のようなデータがある場合:
_constant_id company_id object_id property_id value
1 1 null null foo
1 1 1 null bar
1 1 1 1 baz
_
最初の2つの行をエラーなしで無限に複製できますが、これは明らかに望ましくありません。
この構造のアイデアは、会社ごと、会社内のオブジェクトごと、会社内のプロパティごとにグローバルに定数をバインドできるようにするが、それぞれに一意の定数のみを許可することです。
外部キーと単純なテーブル構造を維持しながら、データベースでこれを解決する方法はありますか?私はtype ENUM ('company', 'object', 'property'), type_id INT
を実行できることを知っていますが、それによって外部キーとすべての定数に必要な会社IDが失われます。
[MySQL 5.7.6以降が必要なため、これはテストされていません]
上記のコメントには同意しますが、試すことのできるアイデアはまだあります。これはパフォーマンスの点で最良ではないと思いますが、それはあなたが説明している問題を解決します。
アイデアは、NULL
を「0」やその他の値などの具体的な値として扱うキーを追加することです。次に、一意にするフィールドの組み合わせに一意にインデックスを付けます。
MySQL 5.7.6は 生成された列 をサポートします。
_ALTER TABLE b2c_constant_bindings
ADD unique_md5 char(32) AS
(MD5(CONCAT_WS('X', ifnull(constant_id, 0), ifnull(company_id, 0), ifnull(object_id, 0), ifnull(property_id,0))))
UNIQUE;
_
CONCAT
を使用する代わりに、CONCAT(1, 23)
とCONCAT(12, 3)
に似たケースで同じ結果になるのを避けるために_CONCAT_WS
_を使用しています(@Rick Jamesの通知ごとのss )。