Kiri Gabung Dengan Dimana Klausul

162

Saya perlu mengambil semua pengaturan default dari tabel pengaturan tetapi juga mengambil pengaturan karakter jika ada untuk karakter x.

Tapi kueri ini hanya mengambil pengaturan yang karakternya = 1, bukan pengaturan default jika pengguna tidak mengatur siapa pun.

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

Jadi saya perlu sesuatu seperti ini:

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

Di mana kunci 1 dan 2 adalah nilai default ketika kunci 0 berisi nilai default dengan nilai karakter.

Sein Kraft
sumber

Jawaban:

345

The whereklausul adalah penyaringan pergi baris di mana left jointidak berhasil. Pindahkan ke 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'  
Andomar
sumber
55

Saat membuat OUTER JOINs (ANSI-89 atau ANSI-92), lokasi filtrasi penting karena kriteria yang ditentukan dalam ONklausa diterapkan sebelum JOIN dibuat . Kriteria terhadap tabel GABUNG LUAR yang disediakan dalam WHEREklausa diterapkan setelah GABUNGAN dibuat . Ini dapat menghasilkan set hasil yang sangat berbeda. Sebagai perbandingan, tidak masalah bagi INNER BERGABUNG jika kriteria diberikan dalam klausa ONatau WHERE- hasilnya akan sama.

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

Jika saya memahami pertanyaan Anda dengan benar, Anda ingin catatan dari database pengaturan jika mereka tidak memiliki gabungan seberang ke tabel character_settings atau jika catatan yang bergabung memiliki character_id = 1.

Karena itu Anda harus melakukannya

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
Menandai
sumber
7
Itu berisiko mengembalikan positif palsu
OMG Ponies
1
@OMGPonies Saya tidak mengerti, Apa yang mungkin menjadi kasus yang berisiko. Dalam kasus saya, saya menerapkan DAN dengan bergabung dan tidak ada hasil di sana, tetapi ketika saya menggunakan solusi di atas, saya mendapat hasil. Tapi saya ingin yakin tentang masalah yang bisa saya hadapi dengan opsi ini.
Chetan Sharma
2

Anda mungkin lebih mudah untuk memahami dengan menggunakan subquery sederhana

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`

Subquery diperbolehkan untuk mengembalikan null, jadi Anda tidak perlu khawatir tentang GABUNG / DIMANA dalam permintaan utama.

Terkadang, ini berhasil lebih cepat di MySQL, tetapi bandingkan dengan formulir LEFT JOIN untuk melihat mana yang paling cocok untuk Anda.

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

Hasilnya benar berdasarkan pernyataan SQL. Gabung kiri mengembalikan semua nilai dari tabel kanan, dan hanya nilai yang cocok dari tabel kiri.

Kolom ID dan NAME berasal dari tabel sebelah kanan, jadi dikembalikan.

Skor berasal dari tabel kiri, dan 30 dikembalikan, karena nilai ini berkaitan dengan Nama "Aliran". Nama-nama lain adalah NULL karena mereka tidak berhubungan dengan Nama "Aliran".

Di bawah ini akan mengembalikan hasil yang Anda harapkan:

    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 menerapkan filter di tabel sebelah kanan.

Dan
sumber
0

Untuk masalah ini, karena bagi banyak orang lain yang melibatkan sambungan kiri non-sepele seperti sambungan kiri pada tabel gabungan, saya merasa nyaman dan agak lebih mudah dibaca untuk membagi kueri dengan withklausa. Dalam contoh Anda,

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;
P-Gn
sumber