2011-01-20 8 views
103

Muszę pobrać wszystkie domyślne ustawienia z tabeli ustawień, ale także pobrać ustawienie znaku, jeśli istnieje dla znaku x.Lewe połączenie z klauzulą ​​

Ale to zapytanie pobiera tylko te ustawienia, w których znak jest = 1, a nie ustawienia domyślne, jeśli użytkownik nie ustawił nikogo.

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

Więc powinna trzeba coś takiego:

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

Gdzie klucz 1 i 2 są wartościami domyślnymi, gdy klucz 0 zawiera domyślną wartość z wartością znaków.

Odpowiedz

240

Klauzula odfiltrowuje wiersze, w których left join nie powiedzie się. Przenieść go do przyłączenia się:

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

Jeśli rozumiem pytanie poprawnie chcesz rekordy z bazy danych ustawień, jeśli nie mają przystąpić do drugiej stronie stołu character_settings lub gdy dołączył rekord character_id = 1

należy zatem zrobić

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

To ryzykuje powracaniem fałszywych alarmów. –

+0

@OMGPonie Nie rozumiem, jakie mogą być przypadki, w których występuje ryzyko. W moim przypadku zastosowałem AND z łączeniem i nie było wyniku, ale kiedy użyłem powyższego rozwiązania, miałem wyniki. Ale chcę mieć pewność co do problemów, z jakimi mogę się zmierzyć przy tej opcji. –

+0

Dzięki. Dobra odpowiedź. –

41

Dokonując OUTER JOIN (ANSI-89 lub ANSI-92), sprawy lokalizacji filtracji ponieważ kryteria określone w klauzuli ON nanosi przed JOIN jest wykonany. Kryteria względem tabeli OUTER JOINed podanej w klauzuli WHERE są stosowane po wykonaniu JOIN. Może to prowadzić do bardzo różnych zestawów wyników. Dla porównania, nie ma znaczenia dla INNER JOINs, jeśli kryteria podane są w klauzulach ON lub WHERE - wynik będzie taki sam.

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

Może się okazać, że łatwiej zrozumieć za pomocą prostego podkwerenda

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` 

Podzapytanie może zwrócić null, więc nie trzeba się martwić o JOIN/WHERE w zapytaniu głównym .

Czasami to działa szybciej w MySQL, ale porównaj go z formularzem LEFT JOIN, aby zobaczyć, co działa najlepiej dla Ciebie.

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

Wynik jest poprawny na podstawie instrukcji SQL. Lewe sprzężenie zwraca wszystkie wartości z prawej tabeli i tylko pasujące wartości z lewej tabeli.

Kolumny ID i NAZWA znajdują się z prawej tabeli, dlatego są zwracane.

Wynik jest z lewej tabeli, a 30 jest zwracana, ponieważ ta wartość odnosi się do nazwy "Flow". Pozostałe nazwy mają wartość NULL, ponieważ nie odnoszą się do nazwy "Flow".

Poniższa zwróci wynik się spodziewałeś:

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 stosowanie filtra w tabeli po prawej stronie.