ฉันสามารถใช้คำสั่ง CASE ในเงื่อนไข JOIN ได้หรือไม่?


145

รูปภาพต่อไปนี้เป็นส่วนหนึ่งของ Microsoft SQL Server 2008 R2 System Views จากภาพที่เราจะเห็นว่าความสัมพันธ์ระหว่างsys.partitionsและขึ้นอยู่กับมูลค่าของsys.allocation_units sys.allocation_units.typeดังนั้นเพื่อรวมเข้าด้วยกันฉันจะเขียนสิ่งที่คล้ายกันนี้:

SELECT  *
FROM    sys.indexes i
        JOIN sys.partitions p
            ON i.index_id = p.index_id 
        JOIN sys.allocation_units a
            ON CASE
               WHEN a.type IN (1, 3)
                   THEN a.container_id = p.hobt_id 
               WHEN a.type IN (2)
                   THEN a.container_id = p.partition_id
               END 

แต่โค้ดด้านบนให้ข้อผิดพลาดทางไวยากรณ์ ฉันเดาว่าเป็นเพราะCASEคำสั่ง ใครก็ได้ช่วยอธิบายหน่อย


เพิ่มข้อความแสดงข้อผิดพลาด:

ข่าวสารเกี่ยวกับ 102 ระดับ 15 สถานะ 1 บรรทัด 6 ไวยากรณ์ไม่ถูกต้องใกล้ '='

นี่คือภาพ


39
คุณใช้ซอฟต์แวร์อะไรในการสร้างแผนภาพ DB ที่สวยงามนี้
LearnByReading

2
@LearnByReading คุณเคยรู้ไหมว่าซอฟต์แวร์ใดถูกใช้?
User632716

1
@ User632716 ไม่น่าเสียดาย!
LearnByReading

2
@ User632716 แม้ว่าฉันคิดว่ามันเป็น MySQL Workbench จริงๆ แต่ฉันไม่เคยได้รับคำตอบ
LearnByReading

@LearnByReading ฉันไม่รู้ จัดทำโดย Microsoft
แค่ผู้เรียน

คำตอบ:


229

CASEแสดงออกส่งกลับค่าจากTHENส่วนหนึ่งของประโยค คุณสามารถใช้มันได้ดังนี้:

SELECT  * 
FROM    sys.indexes i 
    JOIN sys.partitions p 
        ON i.index_id = p.index_id  
    JOIN sys.allocation_units a 
        ON CASE 
           WHEN a.type IN (1, 3) AND a.container_id = p.hobt_id THEN 1
           WHEN a.type IN (2) AND a.container_id = p.partition_id THEN 1
           ELSE 0
           END = 1

โปรดทราบว่าคุณต้องทำบางอย่างกับค่าที่ส่งคืนเช่นเปรียบเทียบกับ 1 คำสั่งของคุณพยายามที่จะส่งคืนค่าของการมอบหมายหรือทดสอบความเท่าเทียมซึ่งทั้งสองอย่างนี้ไม่สมเหตุสมผลในบริบทของ a CASE/ THENclause (ถ้าBOOLEANเป็นประเภทข้อมูลการทดสอบความเท่าเทียมกันจะสมเหตุสมผล)


@HABO ขอบคุณที่ทำงานให้ฉัน ... แต่ปัญหาคือเมื่อฉันทำสิ่งนี้เงื่อนไขทำให้ล้มเหลว ... โปรดบอกฉันว่าฉันจะทำลายมันได้อย่างไร
Sagar Tandel

1
@SagarTandel - ขอโทษนะฉันไม่เข้าใจ "ล้มเหลว" และ "ฉันจะทำลายมันได้อย่างไร" คุณช่วยชี้แจงความคิดเห็นของคุณได้ไหม (เพิ่งโผล่ขึ้นมาจากการดำน้ำจากปลาซาบะอาจจะเป็น Nitrox)
HABO

ตรวจสอบเงื่อนไขทั้งหมดที่ฉันไม่ต้องการ ฉันต้องการให้มันออกจากกรณีที่ตรงกับเงื่อนไข
Sagar Tandel

3
@SagarTandel - จากMSDN : "คำสั่ง CASE ประเมินเงื่อนไขตามลำดับและหยุดด้วยเงื่อนไขแรกที่เงื่อนไขเป็นที่พอใจ" หากคุณต้องการให้แถวที่เข้าร่วมทั้งหมดไม่ตรงกับเงื่อนไขที่ระบุไว้อย่างชัดเจนเพียงแค่เปลี่ยนส่วนท้ายจาก= 1เป็น= 0แต่ฉันไม่คิดว่าคุณจะชอบผลลัพธ์
HABO

เข้าร่วม sys.allocation_units a ON CASE WHEN a.type IN (1, 3) และ a.container_id = p.hobt_id แล้ว 1 เมื่อ a.type IN (2) และ a.container_id = p.partition_id แล้ว 1 ELSE 0 END = 1 คุณช่วยเขียนในกรอบเอนทิตีด้านบนของโซลูชันของคุณได้
ไหม

39

แต่คุณเพียงแค่เข้าร่วมทั้งสองตารางและในส่วนคำสั่ง SELECT ของคุณให้ส่งคืนข้อมูลจากตารางที่ตรงกับ:

ฉันแนะนำให้คุณไปที่ลิงค์นี้Conditional Joins ใน SQL ServerและT-SQL Case Statement ใน JOIN ON Clause

เช่น

    SELECT  *
FROM    sys.indexes i
        JOIN sys.partitions p
            ON i.index_id = p.index_id 
        JOIN sys.allocation_units a
            ON a.container_id =
            CASE
               WHEN a.type IN (1, 3)
                   THEN  p.hobt_id 
               WHEN a.type IN (2)
                   THEN p.partition_id
               END 

แก้ไข: ตามความคิดเห็น

คุณไม่สามารถระบุเงื่อนไขการเข้าร่วมได้ในขณะที่คุณกำลังทำอยู่ .. ตรวจสอบข้อความค้นหาด้านบนว่าไม่มีข้อผิดพลาด ฉันได้นำคอลัมน์ทั่วไปออกแล้วและค่าของคอลัมน์ด้านขวาจะได้รับการประเมินตามเงื่อนไข


1
สิ่งที่conditional joinหมายถึงอะไร? การเข้าร่วมแต่ละครั้ง (ไม่รวมครอส) เป็นเงื่อนไข กรณีนี้แตกต่างจากที่อื่นอย่างไร? ตัวอย่างของคุณมีการรวมภายในด้วยเงื่อนไขเช่นเดียวกับแบบสอบถาม OPs ได้เข้าร่วมกับเงื่อนไข
zerkms

@zerkms: ฉันยอมรับฟังดูสับสน ฉันเชื่อว่าการเข้าร่วมแบบมีเงื่อนไขในบริบทนี้หมายถึงการเข้าร่วมที่มีเงื่อนไขขึ้นอยู่กับเงื่อนไขอื่น
Andriy M

@ Andriy M: มีเหตุผลอะไรที่จะคิดถึงคำศัพท์อื่นสำหรับเงื่อนไขเล็กน้อยด้วยOR?
zerkms

@zerkms: เอ่อใช่เพราะมันฟังดูสับสน :) แต่ฉันเชื่อว่าคุณตั้งใจถามว่ามีเหตุผลใดที่ไม่คิดถึงคำศัพท์อื่นซึ่งในกรณีนี้ฉันไม่แน่ใจ หากคุณกำลังถามหาเหตุผลของฉันฉันคิดว่าฉันคงไม่ใส่ใจมากพอ :) แล้วการรวมกับเงื่อนไขอื่นล่ะ? ฉันกลัวว่าฉันจะบัญญัติศัพท์ไม่เก่ง อย่างไรก็ตามโปรดทราบว่าแนวคิดนี้เกี่ยวกับ "เงื่อนไขตามเงื่อนไข" ไม่ใช่เกี่ยวกับ "เงื่อนไขที่มีOR" การใช้ORเป็นเพียงวิธีหนึ่งในการนำไปใช้
Andriy M

@Andriy M: โอเค แต่ส่วนตัวผมก็ยังไม่เห็นเหตุผลที่จะให้ชื่อสำหรับเล็กน้อยสภาพ 1 ORและ 2 ANDsหรือ CASE1 เป็นแบบสอบถามประจำที่ไม่มีอะไรแตกต่างจากที่อื่น
zerkms

17

ลองสิ่งนี้:

...JOIN sys.allocation_units a ON 
  (a.type=2 AND a.container_id = p.partition_id)
  OR (a.type IN (1, 3) AND a.container_id = p.hobt_id)

แม้ว่าจะได้ผล แต่ข้อความค้นหาในคำถามก็ดูใช้ได้อย่างสมบูรณ์ ดังนั้นยังไม่อธิบายว่ามีอะไรผิดปกติกับรหัสของ OP
zerkms

10

ฉันคิดว่าคุณต้องการคำแถลงสองกรณี:

SELECT  *
FROM    sys.indexes i
    JOIN sys.partitions p
        ON i.index_id = p.index_id 
    JOIN sys.allocation_units a
        ON 
        -- left side of join on statement
            CASE
               WHEN a.type IN (1, 3)
                   THEN a.container_id
               WHEN a.type IN (2)
                   THEN a.container_id
            END 
        = 
        -- right side of join on statement
            CASE
               WHEN a.type IN (1, 3)
                   THEN p.hobt_id
               WHEN a.type IN (2)
                   THEN p.partition_id
            END             

นี้เป็นเพราะ:

  • คำสั่ง CASE ส่งคืนค่าเดียวที่ END
  • คำสั่ง ON เปรียบเทียบสองค่า
  • คำสั่ง CASE ของคุณกำลังทำการเปรียบเทียบภายในคำสั่ง CASE ฉันเดาว่าถ้าคุณใส่คำสั่ง CASE ใน SELECT คุณจะได้รับบูลีน '1' หรือ '0' ซึ่งระบุว่าคำสั่ง CASE ประเมินว่าเป็นจริงหรือเท็จ

5

ฉันเอาตัวอย่างของคุณและแก้ไข:

SELECT  *
FROM    sys.indexes i
    JOIN sys.partitions p
        ON i.index_id = p.index_id 
    JOIN sys.allocation_units a
        ON a.container_id = (CASE
           WHEN a.type IN (1, 3)
               THEN p.hobt_id 
           WHEN a.type IN (2)
               THEN p.partition_id
           ELSE NULL
           END)

1

ดูเหมือนจะดี

https://bytes.com/topic/sql-server/answers/881862-joining-different-tables-based-condition

FROM YourMainTable
LEFT JOIN AirportCity DepCity ON @TravelType = 'A' and DepFrom =  DepCity.Code
LEFT JOIN AirportCity DepCity ON @TravelType = 'B' and SomeOtherColumn = SomeOtherColumnFromSomeOtherTable

ลองทำเช่นนี้ฉันได้รับข้อผิดพลาด: มีการระบุชื่อสหสัมพันธ์ 'xx' หลายครั้งในส่วนคำสั่ง FROM
Etienne

1

ใช่คุณสามารถ. นี่คือตัวอย่าง

SELECT a.*
FROM TableA a
LEFT OUTER JOIN TableB j1 ON  (CASE WHEN LEN(COALESCE(a.NoBatiment, '')) = 3 
                                THEN RTRIM(a.NoBatiment) + '0' 
                                ELSE a.NoBatiment END ) = j1.ColumnName 

1
แม้ว่ารหัสนี้อาจช่วยแก้ปัญหาได้รวมถึงคำอธิบายว่าทำไมจึงแก้ปัญหานี้ได้จะช่วยปรับปรุงคุณภาพของโพสต์ของคุณได้อย่างแท้จริงและอาจส่งผลให้มีการโหวตเพิ่มขึ้น จำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตไม่ใช่แค่คนที่ถามตอนนี้ โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายและระบุข้อ จำกัด และสมมติฐานที่ใช้
เสียงบี๊บสองครั้ง

0

เอาตัวอย่าง DonkeyKong

ปัญหาคือฉันจำเป็นต้องใช้ตัวแปรที่ประกาศ สิ่งนี้ช่วยให้ระบุด้านซ้ายและขวาของสิ่งที่คุณต้องการเปรียบเทียบ ใช้สำหรับรองรับรายงาน SSRS ที่ต้องเชื่อมโยงช่องต่างๆตามการเลือกของผู้ใช้

กรณีเริ่มต้นตั้งค่าตัวเลือกฟิลด์ตามการเลือกจากนั้นฉันสามารถตั้งค่าฟิลด์ที่ฉันต้องการจับคู่สำหรับการเข้าร่วม

สามารถเพิ่มคำสั่งกรณีที่สองสำหรับด้านขวามือหากต้องการตัวแปรเพื่อเลือกจากฟิลด์ต่างๆ

LEFT OUTER JOIN Dashboard_Group_Level_Matching ON
       case
         when @Level  = 'lvl1' then  cw.Lvl1
         when @Level  = 'lvl2' then  cw.Lvl2
         when @Level  = 'lvl3' then  cw.Lvl3
       end
    = Dashboard_Group_Level_Matching.Dashboard_Level_Name

0

ที่นี่ฉันได้เปรียบเทียบความแตกต่างในสองชุดผลลัพธ์ที่แตกต่างกัน:

SELECT main.ColumnName, compare.Value PreviousValue,  main.Value CurrentValue
FROM 
(
    SELECT 'Name' AS ColumnName, 'John' as Value UNION ALL
    SELECT 'UserName' AS ColumnName, 'jh001' as Value UNION ALL
    SELECT 'Department' AS ColumnName, 'HR' as Value UNION ALL
    SELECT 'Phone' AS ColumnName, NULL as Value UNION ALL
    SELECT 'DOB' AS ColumnName, '1993-01-01' as Value UNION ALL
    SELECT 'CreateDate' AS ColumnName, '2017-01-01' as Value UNION ALL
    SELECT 'IsActive' AS ColumnName, '1' as Value
) main
INNER JOIN
(
    SELECT 'Name' AS ColumnName, 'Rahul' as Value UNION ALL
    SELECT 'UserName' AS ColumnName, 'rh001' as Value UNION ALL
    SELECT 'Department' AS ColumnName, 'HR' as Value UNION ALL
    SELECT 'Phone' AS ColumnName, '01722112233' as Value UNION ALL
    SELECT 'DOB' AS ColumnName, '1993-01-01' as Value UNION ALL
    SELECT 'CreateDate' AS ColumnName, '2017-01-01' as Value UNION ALL
    SELECT 'IsActive' AS ColumnName, '1' as Value
) compare
ON main.ColumnName = compare.ColumnName AND
CASE 
    WHEN main.Value IS NULL AND compare.Value IS NULL THEN 0
    WHEN main.Value IS NULL AND compare.Value IS NOT NULL THEN 1
    WHEN main.Value IS NOT NULL AND compare.Value IS NULL THEN 1
    WHEN main.Value <> compare.Value THEN 1
END = 1 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.