Where句を使用した左結合


162

設定テーブルからすべてのデフォルト設定を取得する必要がありますが、x文字に存在する場合は文字設定も取得する必要があります。

ただし、このクエリは、文字が1である設定のみを取得します。ユーザーが誰も設定していない場合、デフォルト設定ではありません。

SELECT `settings`.*, `character_settings`.`value`
FROM (`settings`)
LEFT JOIN `character_settings` 
ON `character_settings`.`setting_id` = `settings`.`id`
WHERE `character_settings`.`character_id` = '1'  

だから私はこのようなものが必要です:

array(
    '0' => array('somekey' => 'keyname', 'value' => 'thevalue'),
    '1' => array('somekey2' => 'keyname2'),
    '2' => array('somekey3' => 'keyname3')
)

ここで、キー1と2は、キー0に文字値を持つデフォルト値が含まれている場合のデフォルト値です。

回答:


344

where句は行離れてフィルタリングされleft join成功していませんが。結合に移動します。

SELECT  `settings`.*, `character_settings`.`value`
FROM    `settings`
LEFT JOIN 
       `character_settings` 
ON     `character_settings`.`setting_id` = `settings`.`id`
        AND `character_settings`.`character_id` = '1'  

55

OUTER JOIN(ANSI-89またはANSI-92)を作成する場合、JOINが作成ONされるに、句で指定された基準が適用されるため、フィルターの場所が重要になります。WHERE句に指定されたOUTER JOINされたテーブルに対する基準は、JOINが行われた後に適用さます。これにより、非常に異なる結果セットが生成される可能性があります。比較すると、ONor WHERE句で条件が指定されていても、INNER JOINは関係ありません。結果は同じです。

  SELECT  s.*, 
          cs.`value`
     FROM SETTINGS s
LEFT JOIN CHARACTER_SETTINGS cs ON cs.setting_id = s.id
                               AND cs.character_id = 1

21

私があなたの質問を正しく理解している場合、character_settingsテーブルへの結合がない場合、またはその結合されたレコードにcharacter_id = 1がある場合は、設定データベースのレコードが必要です。

したがって、あなたはすべきです

SELECT `settings`.*, `character_settings`.`value`
FROM (`settings`)
LEFT OUTER JOIN `character_settings` 
ON `character_settings`.`setting_id` = `settings`.`id`
WHERE `character_settings`.`character_id` = '1' OR
`character_settings`.character_id is NULL

7
これは誤検知を返すリスクがあります
OMGポニー2011年

1
@OMGPoniesわからない、リスクがあるのか​​もしれない。私の場合、結合でANDを適用し、結果はありませんでしたが、上記のソリューションを使用すると、結果が得られました。しかし、私はこのオプションで直面する可能性のある問題について確認したいと思います。
Chetan Sharma 2014

2

単純なサブクエリを使用すると、理解しやすいかもしれません

SELECT `settings`.*, (
    SELECT `value` FROM `character_settings`
    WHERE `character_settings`.`setting_id` = `settings`.`id`
      AND `character_settings`.`character_id` = '1') AS cv_value
FROM `settings`

サブクエリはnullを返すことができるので、メインクエリのJOIN / WHEREについて心配する必要はありません。

場合によっては、これはMySQLでより高速に動作しますが、LEFT JOINフォームと比較して、何が最適かを確認してください。

SELECT s.*, c.value
FROM settings s
LEFT JOIN character_settings c ON c.setting_id = s.id AND c.character_id = '1'

1

結果は、SQLステートメントに基づいて正しいです。左結合は、右のテーブルからすべての値を返し、左のテーブルから一致する値のみを返します。

ID列とNAME列は右側のテーブルにあるため、返されます。

スコアは左のテーブルからのものであり、この値は名前「フロー」に関連するため、30が返されます。他の名前は名前「フロー」に関連しないため、NULLです。

以下はあなたが期待していた結果を返します:

    SELECT  a.*, b.Score
FROM    @Table1 a
    LEFT JOIN @Table2 b
       ON a.ID = b.T1_ID 
WHERE 1=1
AND a.Name = 'Flow'

SQLは右側のテーブルにフィルターを適用します。


0

この問題については、内部結合テーブルでの左結合などの重要な左結合に関係する他の多くの場合と同様に、クエリをwith句で分割する方が便利で読みやすいと思います。あなたの例では、

with settings_for_char as (
  select setting_id, value from character_settings where character_id = 1
)
select
  settings.*,
  settings_for_char.value
from
  settings
  left join settings_for_char on settings_for_char.setting_id = settings.id;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.