เข้าร่วมซ้ายกับส่วนคำสั่งที่


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

เมื่อทำการเชื่อม outer (ANSI-89 หรือ ANSI-92) เรื่องที่ตั้งกรองเพราะเกณฑ์ที่ระบุไว้ในONข้อถูกนำไปใช้ก่อนที่จะเข้าร่วมทำ เกณฑ์เทียบกับตาราง OUTER JOINed ที่ให้ไว้ในส่วนWHEREคำสั่งจะถูกนำไปใช้หลังจากที่ทำ 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

หากฉันเข้าใจคำถามของคุณอย่างถูกต้องคุณต้องการบันทึกจากฐานข้อมูลการตั้งค่าหากพวกเขาไม่มีการเข้าร่วมไปยังตาราง 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 Ponies

1
@OMGP คนที่ฉันไม่เข้าใจอาจมีความเสี่ยงอะไรบ้าง ในกรณีของฉันฉันใช้และด้วยการเข้าร่วมและไม่มีผลลัพธ์อยู่ที่นั่น แต่เมื่อฉันใช้วิธีแก้ปัญหาข้างต้นฉันก็มีผลลัพธ์ แต่ฉันต้องการให้แน่ใจเกี่ยวกับปัญหาที่ฉันสามารถเผชิญกับตัวเลือกนี้
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 ดังนั้นคุณไม่ต้องกังวลกับการเข้าร่วม / 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 เนื่องจากไม่เกี่ยวข้องกับชื่อ "Flow"

ด้านล่างจะส่งคืนผลลัพธ์ที่คุณคาดหวัง:

    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.