SQL: IF clause ภายใน WHERE clause


203

เป็นไปได้ไหมที่จะใช้ประโยคIFภายในWHERE clause ใน MS SQL?

ตัวอย่าง:

WHERE
    IF IsNumeric(@OrderNumber) = 1
        OrderNumber = @OrderNumber
    ELSE
        OrderNumber LIKE '%' + @OrderNumber + '%'

คำตอบ:


212

ใช้คำสั่งCASE
UPDATE:ไวยากรณ์ก่อนหน้า (ตามที่อธิบายโดยบางคน) ไม่ทำงาน คุณสามารถใช้ CASE ได้ดังต่อไปนี้:

WHERE OrderNumber LIKE
  CASE WHEN IsNumeric(@OrderNumber) = 1 THEN 
    @OrderNumber 
  ELSE
    '%' + @OrderNumber
  END

หรือคุณสามารถใช้คำสั่ง IF เช่น @ NJ Reedชี้ให้เห็น


[หมายเหตุหลัง UPDATE โดยผู้แต่ง]: ควรใช้งานได้ แต่คุณควรจะตัด () ทั้งสองด้านเพื่อให้แน่ใจว่าพบการแข่งขัน ฉันมีความรู้สึกว่ามีกรณีที่หายากที่ยังไม่เข้าคู่
Euro Micelli

1
การใช้CASEเป็นวิธีแก้ปัญหาที่เหมาะสมในกรณีส่วนใหญ่ ในกรณีของฉันฉันต้องการเปลี่ยนแปลงตัวดำเนินการเปรียบเทียบและด้วยเหตุนี้ฉันจึงใช้วิธีการถัดไป
Birla

142

คุณควรจะสามารถทำได้โดยไม่มี IF หรือ CASE

 WHERE 
   (IsNumeric(@OrderNumber) AND
      (CAST OrderNumber AS VARCHAR) = (CAST @OrderNumber AS VARCHAR)
 OR
   (NOT IsNumeric(@OrderNumber) AND
       OrderNumber LIKE ('%' + @OrderNumber))

ทั้งนี้ขึ้นอยู่กับรสชาติของ SQL คุณอาจต้องปรับแต่ง casts ตามหมายเลขคำสั่งไปที่ INT หรือ VARCHAR ทั้งนี้ขึ้นอยู่กับว่ารองรับ casts โดยปริยายหรือไม่

นี่เป็นเทคนิคที่พบบ่อยมากใน WHERE clause หากคุณต้องการใช้ตรรกะ "IF" บางอย่างใน WHERE clause ทั้งหมดที่คุณต้องทำคือการเพิ่มเงื่อนไขพิเศษด้วยบูลีนและในส่วนที่จำเป็นต้องใช้


2
ฉันคิดว่าคุณจะได้รับประสิทธิภาพที่เหนือกว่าโซลูชัน CASE แต่เนื่องจากเงื่อนไขเหล่านี้ทั้งหมดได้รับการประเมินไม่ใช่หรือไม่
Kevin Fairchild

ฉันมักจะลืมว่าใน SQL หนึ่งสามารถแทนที่งบเงื่อนไขด้วยตรรกะแบบบูลเช่นนั้น ขอบคุณสำหรับการเตือนความจำมันเป็นเทคนิคที่มีประโยชน์มาก!
CodexArcanum

1
วิธีนี้เป็นทางออกที่ดีที่สุดเนื่องจากเซิร์ฟเวอร์ SQL ประมวลผลตรรกะบูลีน คำสั่ง CASE ที่ซึ่งอนุประโยคมีประสิทธิภาพน้อยกว่ากรณีบูลีนเนื่องจากหากการตรวจสอบครั้งแรกล้มเหลว SQL จะหยุดการประมวลผลบรรทัดและดำเนินการต่อ ที่ช่วยให้คุณประหยัดเวลาในการประมวลผล นอกจากนี้ควรวางงบที่มีราคาแพงกว่าในอีกด้านหนึ่งของการตรวจสอบบูลีนของคุณ
Steve

ขอบคุณสำหรับการแก้ปัญหาที่สง่างามมาก พบการสอนเกี่ยวกับวิธีการที่คุณใช้ซึ่งอาจช่วยให้ผู้คน weblogs.sqlteam.com/jeffs/archive/2003/11/14/513.aspx
Rich

1
@Kash ลิงก์ที่คุณให้มีการลงทะเบียนเพื่ออ่านมี documenation สาธารณะที่อธิบายสิ่งที่คุณพูดหรือไม่
Steve

29

คุณไม่จำเป็นต้องมีคำสั่ง IF เลย

WHERE
    (IsNumeric(@OrderNumber) = 1 AND OrderNumber = @OrderNumber)
OR (IsNumeric(@OrderNumber) = 0 AND OrderNumber LIKE '%' + @OrderNumber + '%')

2
ฉันชอบวิธีนี้มาก Alternativ ใช้: กรองเฉพาะถ้า AdmUseId มีค่า: where (@AdmUserId is null or CurrentOrder.CustomerAdmUserId = @AdmUserId) หรือกรองเฉพาะถ้า IncludeDeleted = 0: where (@IncludeDeleted = 1 or ItemObject.DeletedFlag = 0)
Kasper Halvas Jensen

สิ่งนี้ทำงานได้ดีเมื่อใช้ตัวกรอง IN ภายในส่วนคำสั่ง WHERE มันทำให้เรื่องยุ่งกับกรณีนี้เพราะคุณต้องใช้ COALESCE และมันยากที่จะอ่านในขณะที่นี่เป็นตรรกะที่ตรงไปตรงมาเพื่ออ่าน คำสั่งกรณี TSQL ในส่วนคำสั่ง WHERE สำหรับตัวกรอง NOT IN หรือ IN
pholcroft

14

ไม่มีวิธีที่ดีในการทำเช่นนี้ใน SQL วิธีการบางอย่างที่ฉันได้เห็น:

1) ใช้ CASE รวมกับตัวดำเนินการบูลีน:

WHERE
    OrderNumber = CASE 
        WHEN (IsNumeric(@OrderNumber) = 1)
        THEN CONVERT(INT, @OrderNumber)
        ELSE -9999 -- Some numeric value that just cannot exist in the column
    END
    OR 
    FirstName LIKE CASE
        WHEN (IsNumeric(@OrderNumber) = 0)
        THEN '%' + @OrderNumber
        ELSE ''
    END

2) ใช้ IF นอกตัวเลือก

IF (IsNumeric(@OrderNumber)) = 1
BEGIN
    SELECT * FROM Table
    WHERE @OrderNumber = OrderNumber
END ELSE BEGIN
    SELECT * FROM Table
    WHERE OrderNumber LIKE '%' + @OrderNumber
END

3) การใช้สตริงยาวเขียนคำสั่ง SQL ของคุณอย่างมีเงื่อนไขแล้วใช้ EXEC

วิธีที่ 3 นั้นน่ากลัว แต่เกือบจะเป็นความคิดเดียวที่ใช้ได้ผลถ้าคุณมีเงื่อนไขหลายอย่างเช่นนั้น


วิธีที่สี่คือการแปลงIF...ELSE...เงื่อนไขทั้งหมดของคุณเป็นบูลีนANDและORใน @ njr101 คำตอบข้างต้น ข้อเสียของ ^ วิธีนี้คือมันอาจเป็นเรื่องยากหากสมองของคุณมีหลายคนIFหรือถ้าคุณมีหลายอย่างที่ซ้อนกัน
Don Cheadle



3

ฉันคิดว่าที่ ... เช่น / = ... กรณี ... จากนั้น ... สามารถทำงานกับ Booleans ฉันใช้ T-SQL

สถานการณ์สมมติ: สมมติว่าคุณต้องการรับงานอดิเรกของ Person-30 ถ้าบูลเป็นเท็จและงานอดิเรกของ Person-42 ถ้าบูลเป็นจริง (ตามที่กล่าวมาการค้นหางานอดิเรกประกอบด้วยมากกว่า 90% ของรอบการคำนวณทางธุรกิจ

CREATE PROCEDURE sp_Case
@bool   bit
AS
SELECT Person.Hobbies
FROM Person
WHERE Person.ID = 
    case @bool 
        when 0 
            then 30
        when 1
            then 42
    end;

2
WHERE (IsNumeric (@OrderNumber) <> 1 หรือ OrderNumber = @OrderNumber) 
             AND (IsNumber (@OrderNumber) = 1 หรือหมายเลขคำสั่งซื้อเช่น '%' 
                                              + @OrderNumber + '%')

เขียนกฎเชื่อมต่อแบบปกติ:IF P THEN Q ELSE R <=> ( ( NOT P ) OR Q ) AND ( P OR R )
onedaywhen

1

คำชี้แจงกรณีเป็นตัวเลือกที่ดีกว่าถ้าเสมอ

  WHERE  vfl.CreatedDate >= CASE WHEN @FromDate IS NULL THEN vfl.CreatedDate ELSE  @FromDate END
    AND vfl.CreatedDate<=CASE WHEN @ToDate IS NULL THEN vfl.CreatedDate ELSE @ToDate END 

1
    WHERE OrderNumber LIKE CASE WHEN IsNumeric(@OrderNumber) = 1 THEN @OrderNumber ELSE  '%' + @OrderNumber END

ในกรณีบรรทัดสภาพจะทำงานอย่างถูกต้อง


0

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

USE AdventureWorks2012;
GO
DECLARE @AvgWeight decimal(8,2), @BikeCount int
IF 
(SELECT COUNT(*) FROM Production.Product WHERE Name LIKE 'Touring-3000%' ) > 5
BEGIN
   SET @BikeCount = 
        (SELECT COUNT(*) 
         FROM Production.Product 
         WHERE Name LIKE 'Touring-3000%');
   SET @AvgWeight = 
        (SELECT AVG(Weight) 
         FROM Production.Product 
         WHERE Name LIKE 'Touring-3000%');
   PRINT 'There are ' + CAST(@BikeCount AS varchar(3)) + ' Touring-3000 bikes.'
   PRINT 'The average weight of the top 5 Touring-3000 bikes is ' + CAST(@AvgWeight AS varchar(8)) + '.';
END
ELSE 
BEGIN
SET @AvgWeight = 
        (SELECT AVG(Weight)
         FROM Production.Product 
         WHERE Name LIKE 'Touring-3000%' );
   PRINT 'Average weight of the Touring-3000 bikes is ' + CAST(@AvgWeight AS varchar(8)) + '.' ;
END ;
GO

การใช้คำสั่ง IF ... ซ้อนกันตัวอย่างต่อไปนี้แสดงให้เห็นว่าคำสั่ง IF … ELSE สามารถซ้อนอยู่ภายในอีกคำสั่งได้อย่างไร ตั้งค่าตัวแปร @Number เป็น 5, 50 และ 500 เพื่อทดสอบแต่ละคำสั่ง

DECLARE @Number int
SET @Number = 50
IF @Number > 100
   PRINT 'The number is large.'
ELSE 
   BEGIN
      IF @Number < 10
      PRINT 'The number is small'
   ELSE
      PRINT 'The number is medium'
   END ;
GO

2
ดูเหมือนจะไม่เกี่ยวข้องกัน ไม่ใช้ IF (หรือรหัสที่มีเงื่อนไขใด ๆ ) ในส่วนคำสั่ง WHERE
Vince Bowdren

0

ในเซิร์ฟเวอร์ sql ฉันมีปัญหาเดียวกันฉันต้องการใช้และคำสั่งเฉพาะถ้าพารามิเตอร์เป็นเท็จและจริงฉันต้องแสดงทั้งค่าจริงและเท็จดังนั้นฉันจึงใช้วิธีนี้

(T.IsPublic = @ShowPublic or  @ShowPublic = 1)

-1
If @LstTransDt is Null
                begin
                    Set @OpenQty=0
                end
            else
                begin
                   Select   @OpenQty=IsNull(Sum(ClosingQty),0)  
                   From  ProductAndDepotWiseMonitoring  
                   Where   Pcd=@PCd And PtpCd=@PTpCd And TransDt=@LstTransDt      
                end 

ดูว่าสิ่งนี้จะช่วยให้


-6
USE AdventureWorks2012;
GO
IF 
(SELECT COUNT(*) FROM Production.Product WHERE Name LIKE 'Touring-3000%' ) > 5
PRINT 'There are more than 5 Touring-3000 bicycles.'
ELSE PRINT 'There are 5 or less Touring-3000 bicycles.' ;
GO

ดูเหมือนจะไม่เกี่ยวข้องกัน ไม่ใช้ IF (หรือรหัสที่มีเงื่อนไขใด ๆ ) ในส่วนคำสั่ง WHERE
Vince Bowdren
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.