Залишився приєднатися до пункту де


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 містить значення за замовчуванням зі значенням символу.

Відповіді:


346

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

При здійсненні зовнішніх з'єднань (ANSI-89 або ANSI-92) розташування фільтрації має значення, оскільки критерії, визначені в ONпункті, застосовуються до того, як ПРИЄДНАЙТЕСЬ . Критерії проти таблиці OUTER JOINed, наведеної в WHEREпункті, застосовуються після того, як буде виконано приєднання . Це може створити дуже різні набори результатів. Для порівняння, для INNER JOIN не має значення, якщо критерії передбачені в 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

21

Якщо я правильно розумію ваше запитання, ви хочете записувати з бази даних налаштувань, якщо вони не мають спільного з'єднання з таблицею параметрів символів або якщо ця об'єднана запис має символ_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 Ponies

1
@OMGPonies Я не розумію. Які можуть бути випадки, коли це має ризики. У моєму випадку я застосував AND з приєднанням, і результату не було, але коли я застосував вище рішення, у мене були результати. Але я хочу бути впевненим у питаннях, з якими я можу зіткнутися з цим варіантом.
Chetan Sharma

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. Ліве з'єднання повертає всі значення з правої таблиці, а лише відповідні значення з лівої таблиці.

Стовпці ідентифікатора та 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;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.