SQL: JIKA klausa dalam klausa WHERE


203

Apakah mungkin untuk menggunakan klausa IF dalam klausa WHERE di MS SQL?

Contoh:

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

Jawaban:


212

Gunakan UPDATE pernyataan KASUS
: Sintaks sebelumnya (seperti yang ditunjukkan oleh beberapa orang) tidak berfungsi. Anda dapat menggunakan CASE sebagai berikut:

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

Atau Anda dapat menggunakan pernyataan IF seperti @ NJ Reed tunjukkan.


[Catatan setelah PEMBARUAN oleh penulis]: Itu seharusnya berhasil, tetapi Anda harus TRIM () kedua belah pihak untuk memastikan bahwa kecocokan ditemukan. Saya punya firasat bahwa masih ada kasus tepi yang gagal untuk mencocokkan.
Euro Micelli

1
Menggunakan CASEadalah solusi yang tepat dalam banyak kasus. Dalam kasus saya, saya ingin mengubah operator perbandingan dan karenanya saya menggunakan pendekatan berikutnya.
Birla

142

Anda harus dapat melakukan ini tanpa JIKA atau KASUS

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

Tergantung pada rasa SQL Anda mungkin perlu mengubah gips pada nomor pesanan ke INT atau VARCHAR tergantung pada apakah gips implisit didukung.

Ini adalah teknik yang sangat umum dalam klausa WHERE. Jika Anda ingin menerapkan beberapa logika "JIKA" di klausa WHERE yang perlu Anda lakukan adalah menambahkan kondisi ekstra dengan boolean DAN ke bagian di mana ia perlu diterapkan.


2
Saya akan membayangkan Anda mengambil sedikit kinerja hit atas solusi CASE, karena semua kondisi tersebut dievaluasi, bukan?
Kevin Fairchild

Saya selalu lupa bahwa dalam SQL seseorang dapat mengganti pernyataan bersyarat dengan logika boolean seperti itu. Terima kasih atas pengingatnya, ini adalah teknik yang sangat berguna!
CodexArcanum

1
Solusi ini sebenarnya yang terbaik karena cara SQL server memproses logika boolean. Pernyataan CASE di mana klausa kurang efisien daripada kasus boolean karena jika pemeriksaan pertama gagal, SQL akan berhenti memproses baris dan melanjutkan. Itu menghemat waktu pemrosesan Anda. Juga, selalu letakkan pernyataan yang lebih mahal di sisi lain cek boolean Anda.
Steve

Terima kasih atas solusi yang sangat elegan. Menemukan tutorial tentang metode yang Anda gunakan yang dapat membantu orang. weblogs.sqlteam.com/jeffs/archive/2003/11/14/513.aspx
Rich

1
@Kash tautan yang Anda berikan adalah register-to-read, adakah dokumentasi yang tersedia untuk umum yang menjelaskan apa yang Anda katakan?
Steve

29

Anda tidak membutuhkan pernyataan IF sama sekali.

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

2
Saya sangat suka pendekatan ini. Alternativ menggunakan: Hanya filter jika AdmUseId memiliki nilai: where (@AdmUserId is null or CurrentOrder.CustomerAdmUserId = @AdmUserId) Atau hanya filter jika IncludeDeleted = 0: where (@IncludeDeleted = 1 or ItemObject.DeletedFlag = 0)
Kasper Halvas Jensen

Ini bekerja dengan baik ketika menggunakan filter IN dalam klausa WHERE. Akan mengacaukan melakukan ini dengan KASUS karena Anda harus menggunakan COALESCE dan sulit untuk membaca, sedangkan ini adalah logika langsung untuk dibaca. Pernyataan KASUS TSQL dalam WHERE clause untuk NOT IN atau IN filter
pholcroft

14

Tidak ada cara yang baik untuk melakukan ini dalam SQL. Beberapa pendekatan yang saya lihat:

1) Gunakan CASE yang dikombinasikan dengan operator 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) Gunakan IF di luar SELECT

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

3) Menggunakan string panjang, buat pernyataan SQL Anda secara kondisional, dan kemudian gunakan EXEC

Pendekatan ke-3 mengerikan, tetapi hampir satu-satunya pemikiran yang berfungsi jika Anda memiliki sejumlah kondisi variabel seperti itu.


pendekatan keempat adalah mengubah semua IF...ELSE...persyaratan Anda menjadi boolean ANDdan ORseperti pada @ njr101 jawaban di atas. Kelemahan dari pendekatan ini adalah sulitnya otak jika Anda memiliki banyak IF, atau jika Anda memiliki banyak yang bersarang
Don Cheadle


4

Anda ingin pernyataan KASUS

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

3

Saya pikir di mana ... suka / = ... huruf ... maka ... dapat bekerja dengan Boolean. Saya menggunakan T-SQL.

Skenario: Katakanlah Anda ingin mendapatkan hobi Person-30 jika bool salah, dan hobi Person-42 jika bool benar. (Menurut beberapa orang, pencarian hobi mencakup lebih dari 90% siklus perhitungan bisnis, jadi perhatikan baik-baik.).

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 ATAU OrderNumber = @OrderNumber) 
             AND (IsNumber (@OrderNumber) = 1 ATAU OrderNumber SUKA '%' 
                                              + @OrderNumber + '%')

Conjunctive Normal Form aturan penulisan ulang:IF P THEN Q ELSE R <=> ( ( NOT P ) OR Q ) AND ( P OR R )
onedaywhen

1

Pernyataan KASUS adalah opsi yang lebih baik daripada JIKA selalu.

  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

Dalam kondisi line case akan bekerja dengan baik.


0

Contoh berikut mengeksekusi kueri sebagai bagian dari ekspresi Boolean dan kemudian mengeksekusi blok pernyataan yang sedikit berbeda berdasarkan hasil dari ekspresi Boolean. Setiap blok pernyataan dimulai dengan BEGIN dan dilengkapi dengan 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

Menggunakan pernyataan IF ... ELSE bersarang Contoh berikut menunjukkan bagaimana pernyataan IF ... ELSE dapat bersarang di dalam yang lain. Atur variabel @Number ke 5, 50, dan 500 untuk menguji setiap pernyataan.

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
Ini sepertinya tidak relevan. Itu tidak menggunakan IF (atau kode kondisional) dalam klausa WHERE.
Vince Bowdren

0

Dalam sql server saya punya masalah yang sama saya ingin menggunakan dan pernyataan hanya jika parameter salah dan benar saya harus menunjukkan nilai benar dan salah jadi saya menggunakannya dengan cara ini

(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 

Lihat apakah ini membantu.


-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

Ini sepertinya tidak relevan. Itu tidak menggunakan IF (atau kode kondisional) dalam klausa WHERE.
Vince Bowdren
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.