まず、ここに投稿する言い訳です。通常、十分な時間をかけて検索することで、状況に対する答えを見つけることができるはずだと感じています...これまでのところ、検索とテストに約 5 時間かかりましたが、結果を説明することはできません。私は得ています。私は現時点でちょっと頭がおかしいです。あなたの誰かが私を助けることができれば、それは非常に高く評価されます.
状況
以下はすべて既存のコードですが、動作を最適化するのに忙しいです。
私は 3 つのテーブルで作業しています。
- 最初のテーブルには項目が含まれ、
- 2 番目のテーブルには、すべての項目のプロパティ フィールドが含まれており、その他のフィールドには名前とデフォルト値があります。
- 3 番目のテーブルには、id によってアイテムにリンクされ、フィールド id によってフィールドにリンクされた、プロパティ フィールドのフィールド値が含まれます。
アイデアは、値を持つ各アイテムのすべてのフィールドを取得することです。フィールドとアイテムの値の行が値テーブルに存在しない場合は、既定値を使用する必要があります。
これはすべて 1 つのクエリで発生する必要があります。
私の前の人は、フィールドが追加されるたびに、デフォルト値フィールドがすべてのアイテムの値テーブルに挿入されるようにすることで、この問題を「修正」しました。データベース テーブルに 10,000 を超えるアイテムと 10 を超えるフィールドを含めることができる場合、これはもちろん間違った方法です。
私のテストケース
このシステムに 2 年以上取り組んできた私は、ついにこの問題を修正する時間を得ることができました。動作中のシステムでの通常のテストでは、常に期待どおりの結果が得られませんでした。これは、社内テスト システムの現在の状態です。
- 277項目の行
- 3 フィールド行
- 824 値行
これは、クリーンアップのために一度だけクエリを実行して、システム上に存在しなくなったアイテムとフィールドの値をクリーンアップした後です (はい、この部分はバグだらけです)。
DELETE FROM values WHERE item_id NOT IN (SELECT id FROM items) OR field_id NOT IN (SELECT id FROM fields);
元のテーブルにはより多くのフィールドが含まれているため、最小限の要件でダミーシステムも作成しました。
-- table a represents items
CREATE TABLE IF NOT EXISTS `a` (
`id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `a` (`id`) VALUES (1),(2),(3);
-- table b represents fields
CREATE TABLE IF NOT EXISTS `b` (
`id` int(11) NOT NULL,
`default` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `b` (`id`, `default`) VALUES
(1, 4),
(2, 5),
(3, 6),
(4, 11),
(5, 12);
-- table c represents values
CREATE TABLE IF NOT EXISTS `c` (
`id` int(11) NOT NULL,
`a_id` int(11) NOT NULL,
`b_id` int(11) NOT NULL,
`value` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `c` (`id`, `a_id`, `b_id`, `value`) VALUES
(1, 1, 1, 7),
(2, 1, 2, 8),
(3, 2, 3, 9),
(4, 2, 1, 7),
(5, 3, 2, 8),
(6, 3, 3, 9),
(7, 1, 5, 13);
期待される結果は 831 行 (277 項目 * 3 フィールド)である必要があり、値テーブルで使用できない項目/フィールドの組み合わせには、値テーブルの値ではなくフィールドの既定値を入力する必要があります。
調査結果を確認するために作成したダミー システムで試した成功したテスト ケース SQL は、期待どおりの結果を返します。
SELECT a.id,
b.id,
IF(c.value IS NOT NULL, c.value, b.default) as t_value
FROM a
join b
LEFT JOIN c on c.a_id = a.id AND c.b_id = b.id
これは、15 行 (3 a (アイテム) x 5 b (フィールド)) を返し、期待されるすべてのデータを含みます。
社内テスト システムのクエリを変更すると、機能するはずでした。これは私が送ったSQLです:
SELECT items.id AS item_id, fields.id AS field_id, IF(values.value IS NULL, fields.default_value, value.value) AS field_value
FROM items
JOIN fields
LEFT JOIN values ON values.item_id = item.id AND values.field_id = fields.id
...しかし、予想される831行ではなく1104行が返されます。テーブルから不正確なデータが削除され、考慮されていない余分なフィールドはSQLでまったく使用されず、さらに抽象テストによりクエリの概念が証明されました。現実的な状況だけが失敗し続けます。
誰かが私の間違いを指摘できれば、それは大歓迎です。ここにあるテーブル名は変更されていますが、リクエストがあれば、問題の社内テスト システム テーブルの部分的なダンプを投稿することもできます。ただし、上記の例は正確なはずです。