これは、子行が一致するメインの親テーブル内のすべての行を検索する必要がある、実行中のクエリの簡略化されたバージョンです。次のクエリは、子テーブルの 1 つが空の場合、結果を返しません。
メイン テーブルには 2 つの子テーブルがあります。
CREATE TABLE main (id INT PRIMARY KEY, name VARCHAR(8));
CREATE TABLE child1(id INT PRIMARY KEY, main_id int, name VARCHAR(8));
ALTER TABLE child1 add constraint fk_child1_main foreign key (main_id) references main (id);
CREATE TABLE child2(id INT PRIMARY KEY, main_id int, name VARCHAR(8));
ALTER TABLE child2 add constraint fk_child2_main foreign key (main_id) references main (id);
INSERT INTO main (id, name) VALUES (1, 'main');
INSERT INTO child1 (id, main_id, name) VALUES (2, 1, 'child1');
child2 には行がなく、空の場合、次のクエリは行を返しません。
SELECT
main.*
FROM
main
INNER JOIN
child1
ON
main.id = child1.main_id
INNER JOIN
child2
ON
main.id = child2.main_id
WHERE
child1.name = 'child1' OR
child2.name = 'DOES NOT EXIST';
行が child2 に追加された場合、それが WHERE 句と一致しなくても、SELECT はメイン テーブルの行を返します。
INSERT INTO child2 (id, main_id, name) VALUES (4, 1, 'child2');
Derby と SQLite でこれをテストしたので、これはデータベースでは一般的なものに見えます。
なぜこれがこのように振る舞うのですか?
修正するにはどうすればよいですか?
UNION の個別の SELECT に変更することもできますが、それははるかに冗長であり、さらに、SQL を動的に生成しているため、コードを変更する必要はありません。
もう 1 つの修正方法は、データベースにダム行を追加することですが、これは面倒です。
PS メイン テーブルは、クライアントが検索するアセットを記録するアセット管理システムのセッション テーブルです。ルックアップにはさまざまな種類があり、種類ごとに個別の子テーブルが取得されます。さらに、検索可能なセッションのキーと値のペアの属性子テーブルがあります。