SQL: Mệnh đề IF trong mệnh đề WHERE


203

Có thể sử dụng mệnh đề IF trong WHERE trong MS SQL không?

Thí dụ:

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

Câu trả lời:


212

Sử dụng câu lệnh CASE
CẬP NHẬT: Cú pháp trước đó (như được chỉ ra bởi một vài người) không hoạt động. Bạn có thể sử dụng CASE như sau:

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

Hoặc bạn có thể sử dụng câu lệnh IF như @ NJ Reed chỉ ra.


[Lưu ý sau khi CẬP NHẬT bởi tác giả]: Điều đó sẽ hoạt động, nhưng bạn nên TRIM () cả hai bên để đảm bảo rằng một trận đấu được tìm thấy. Tôi có một cảm giác ruột rằng hiếm có trường hợp cạnh nào không khớp.
Euro Micelli

1
Sử dụng CASElà giải pháp thích hợp trong hầu hết các trường hợp. Trong trường hợp của tôi, tôi muốn thay đổi toán tử so sánh và do đó tôi đã sử dụng phương pháp tiếp theo.
Birla

142

Bạn sẽ có thể làm điều này mà không cần bất kỳ IF hoặc CASE

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

Tùy thuộc vào hương vị của SQL, bạn có thể cần phải điều chỉnh các phôi trên số thứ tự thành INT hoặc VARCHAR tùy thuộc vào việc các phôi ẩn được hỗ trợ.

Đây là một kỹ thuật rất phổ biến trong mệnh đề WHERE. Nếu bạn muốn áp dụng một số logic "IF" trong mệnh đề WHERE, tất cả những gì bạn cần làm là thêm điều kiện bổ sung với boolean AND vào phần cần áp dụng.


2
Tôi có thể tưởng tượng bạn mất một chút hiệu suất đối với giải pháp CASE, tuy nhiên, vì tất cả các điều kiện đó được đánh giá, phải không?
Kevin Fairchild

Tôi luôn quên rằng trong SQL người ta có thể thay thế các câu lệnh có điều kiện bằng logic boolean như thế. Cảm ơn đã nhắc nhở, đó là một kỹ thuật rất hữu ích!
CodexArcanum

1
Giải pháp này thực sự là giải pháp tốt nhất do cách máy chủ SQL xử lý logic boolean. Các câu lệnh CASE trong đó các mệnh đề kém hiệu quả hơn các trường hợp boolean vì nếu lần kiểm tra đầu tiên thất bại, SQL sẽ dừng xử lý dòng và tiếp tục. Điều đó giúp bạn tiết kiệm thời gian xử lý. Ngoài ra, luôn luôn đặt câu lệnh tốn kém hơn ở phía bên kia của kiểm tra boolean của bạn.
Steve

Cảm ơn cho một giải pháp rất thanh lịch. Tìm thấy một hướng dẫn về phương pháp bạn đã sử dụng có thể giúp mọi người. weblogs.sqlteam.com/jeffs/archive/2003/11/14/513.aspx
Giàu

1
@Kash liên kết bạn cung cấp là một đăng ký để đọc, có bất kỳ thông tin công khai nào có thể mô tả những gì bạn đang nói không?
Steve

29

Bạn không cần một câu lệnh IF nào cả.

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

2
Tôi thực sự thích cách tiếp cận này. Alternativ sử dụng: Chỉ lọc nếu admUseId có giá trị: where (@AdmUserId is null or CurrentOrder.CustomerAdmUserId = @AdmUserId) Hoặc chỉ lọc nếu where (@IncludeDeleted = 1 or ItemObject.DeletedFlag = 0)
Bao gồm xóa

Điều này hoạt động tốt khi sử dụng bộ lọc IN trong mệnh đề WHERE. Nó gây rối khi làm điều này với CASE khi bạn phải sử dụng COALESCE và rất khó đọc, trong khi đây là logic đơn giản để đọc. Câu lệnh TSQL CASE trong mệnh đề WHERE cho bộ lọc KHÔNG IN hoặc IN
pholcroft

14

Không có cách nào tốt để làm điều này trong SQL. Một số cách tiếp cận tôi đã thấy:

1) Sử dụng CASE kết hợp với các toán tử boolean:

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) Sử dụng IF bên ngoài CHỌN

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

3) Sử dụng một chuỗi dài, soạn thảo câu lệnh SQL của bạn một cách có điều kiện và sau đó sử dụng EXEC

Cách tiếp cận thứ 3 thật ghê gớm, nhưng nó gần như chỉ nghĩ rằng nó hoạt động nếu bạn có một số điều kiện khác nhau như thế.


cách tiếp cận thứ tư là chuyển đổi tất cả các IF...ELSE...điều kiện của bạn thành câu trả lời của boolean ANDORnhư trong câu trả lời @ njr101 ở trên. Nhược điểm của ^ phương pháp này là nó có thể rất khó khăn nếu bạn có nhiều người IF, hoặc nếu bạn có nhiều thứ được lồng vào nhau
Don Cheadle


4

Bạn muốn tuyên bố CASE

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

3

Tôi nghĩ rằng nơi ... như / = ... trường hợp ... thì ... có thể hoạt động với Booleans. Tôi đang sử dụng T-SQL.

Kịch bản: Giả sử bạn muốn có được sở thích của Người-30 nếu bool là sai và sở thích của Người-42 nếu bool là đúng. (Theo một số người, tìm kiếm sở thích chiếm hơn 90% các chu kỳ tính toán kinh doanh, vì vậy hãy chú ý chặt chẽ.).

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 HOẶC OrderNumber = @OrderNumber) 
             VÀ (IsNumber (@OrderNumber) = 1 HOẶC Đặt hàngSố THÍCH '%' 
                                              + @OrderNumber + '%')

Quy tắc viết lại hình thức bình thường kết hợp:IF P THEN Q ELSE R <=> ( ( NOT P ) OR Q ) AND ( P OR R )
onedaywhen

1

Tuyên bố CASE là lựa chọn tốt hơn IF luôn.

  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

Trong trường hợp dòng Điều kiện sẽ hoạt động đúng.


0

Ví dụ sau đây thực thi một truy vấn như là một phần của biểu thức Boolean và sau đó thực thi các khối câu lệnh hơi khác nhau dựa trên kết quả của biểu thức Boolean. Mỗi khối câu lệnh bắt đầu bằng BEGIN và hoàn thành với 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

Sử dụng các câu lệnh IF ... ELSE lồng nhau Ví dụ sau đây cho thấy cách một câu lệnh ELSE IF có thể được lồng bên trong một câu lệnh khác. Đặt biến @Number thành 5, 50 và 500 để kiểm tra từng câu lệnh.

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
Điều này dường như không liên quan. Nó không sử dụng IF (hoặc bất kỳ mã điều kiện nào) trong mệnh đề WHERE.
Vince Bowdren

0

Trong máy chủ sql tôi gặp vấn đề tương tự, tôi chỉ muốn sử dụng một câu lệnh và câu lệnh nếu tham số là sai và đúng, tôi phải hiển thị cả hai giá trị đúng và sai vì vậy tôi đã sử dụng nó theo cách này

(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 

Xem nếu điều này giúp.


-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

Điều này dường như không liên quan. Nó không sử dụng IF (hoặc bất kỳ mã điều kiện nào) trong mệnh đề WHERE.
Vince Bowdren
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.