web-dev-qa-db-ja.com

MySQLの*を使用したサブクエリの左結合

JOINステートメントで、かなり単純なクエリとサブクエリを組み合わせています。サブクエリの選択に*を含めた場合にのみ機能します。どうして?

これは機能します

$sql = 'SELECT locations.id, title, name, hours.lobby
        FROM locations
        LEFT JOIN states ON states.id = locations.state_id
        LEFT JOIN (SELECT *, type_id IS NOT NULL AS lobby FROM location_hours) AS hours ON locations.id = hours.location_id
        GROUP BY locations.id';

これはしません

$sql = 'SELECT locations.id, title, name, hours.lobby
        FROM locations
        LEFT JOIN states ON states.id = locations.state_id
        LEFT JOIN (SELECT type_id IS NOT NULL AS lobby FROM location_hours) AS hours ON locations.id = hours.location_id
        GROUP BY locations.id';

私はそれをこのようにすべきですか?すべてのフィールドが必要ない場合、*は最適ではないと思いましたか?

9
MAZUMA

これを試してください(あなたの意図が正しく理解されていれば、nullではなくtype_idでフィルタリングしたかった):

$sql = 'SELECT locations.id, title, name, hours.lobby
        FROM locations
        LEFT JOIN states ON states.id = locations.state_id
        LEFT JOIN (SELECT location_id, type_id AS lobby FROM location_hours 
        WHERE type_id IS NOT NULL) AS hours ON locations.id = hours.location_id
        GROUP BY locations.id';

説明は、外部クエリで参照されているすべてのフィールドを内部クエリで選択する必要があることです。

35
Ashalynd

Type_idにNULL以外の値を設定したいので、LEFT JOINを使用しないでください。標準のJOINを使用する次のものが必要です。

$sql = 'SELECT locations.id, title, name, location_hours.type_id
        FROM locations
        JOIN location_hours ON location_hours.location_id = locations.id
        LEFT JOIN states ON states.id = locations.state_id
        WHERE location_hours.type_id IS NOT NULL
        GROUP BY locations.id';

JOINの要点は、実際に存在する行のみを結合することです。したがって、location_hoursにlocation.idに対応するlocation_idがない行は取得されません。次に、location_hours.type_idのNULL値を除外します。

0
Chill