Left Join With Where Clause

Мне нужно получить все настройки по умолчанию из таблицы настроек, а также захватить настройку символа, если существует для символа x.

Но этот запрос извлекает только те настройки, где символ = 1, а не настройки по умолчанию, если пользователь havent установил кого-либо.

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 содержит значение по умолчанию с символьным значением.

Ответ 1

Предложение 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'  

Ответ 2

При создании ВНУТРЕННИХ СОЕДИНЕНИЙ (ANSI-89 или ANSI-92), место фильтрации имеет значение, потому что критерии, указанные в предложении ON, применяются до того, как JOIN сделан. Критерий в отношении таблицы OUTER JOINed, указанной в предложении WHERE, применяется после создания JOIN. Это может привести к очень различным наборам результатов. Для сравнения это не имеет значения для INNER JOINs, если критерии указаны в предложениях ON или WHERE - результат будет таким же.

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

Ответ 3

Если я правильно понял ваш вопрос, вы хотите, чтобы записи из базы данных параметров, если у них нет присоединения к таблице 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

Ответ 4

Вам может быть проще понять, используя простой подзапрос

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'

Ответ 5

Результат корректен на основе оператора SQL. Left join возвращает все значения из правой таблицы и только соответствующие значения из левой таблицы.

Идентификаторы и столбцы 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 применяет фильтр в правой таблице.