Chuyển đổi / trường hợp SQL trong mệnh đề 'where'


146

Tôi đã cố gắng tìm kiếm xung quanh, nhưng tôi không thể tìm thấy bất cứ điều gì có thể giúp tôi.

Tôi đang cố gắng làm điều này trong SQL:

declare @locationType varchar(50);
declare @locationID int;

SELECT column1, column2
FROM viewWhatever
WHERE
CASE @locationType
    WHEN 'location' THEN account_location = @locationID
    WHEN 'area' THEN xxx_location_area = @locationID
    WHEN 'division' THEN xxx_location_division = @locationID

Tôi biết rằng tôi không nên đặt '= @locationID' vào cuối mỗi cái, nhưng tôi không thể nhận được cú pháp thậm chí gần đúng. SQL tiếp tục phàn nàn về '=' của tôi trên dòng WHEN đầu tiên ...

Tôi có thể làm cái này như thế nào?

Câu trả lời:


191
declare @locationType varchar(50);
declare @locationID int;

SELECT column1, column2
FROM viewWhatever
WHERE
@locationID = 
  CASE @locationType
      WHEN 'location' THEN account_location
      WHEN 'area' THEN xxx_location_area 
      WHEN 'division' THEN xxx_location_division 
  END

1
Như TomH đã lưu ý trong phần bình luận cho câu trả lời của bạn bên dưới, bạn đã hình thành SQL không chính xác. Tôi đã thử nghiệm của tôi trong SQLServer 2005 và nó hoạt động tốt.
Bob Probst

Tại sao @ cần thiết? Họ làm gì?
Tadej

2
@ chỉ ra các biến trong t-sql, nếu không có @, @locationID sẽ được hiểu là tên cột.
Christian Sloper

70

không có tuyên bố trường hợp ...

SELECT column1, column2
FROM viewWhatever
WHERE
    (@locationType = 'location' AND account_location = @locationID)
    OR
    (@locationType = 'area' AND xxx_location_area = @locationID)
    OR
    (@locationType = 'division' AND xxx_location_division = @locationID)

2
Điều này sẽ cho một kết quả hơi khác khi câu lệnh Case thoát sau khi một điều kiện được đáp ứng - nhưng cú pháp OR sẽ đánh giá tất cả các khả năng
vào

1
@tember Ngay cả khi SQL là ngôn ngữ thủ tục, nếu OR đầu tiên là đúng thì phần còn lại của biểu thức sẽ không được đánh giá. Vì SQL là ngôn ngữ khai báo, làm thế nào để bạn biết DBM sẽ đánh giá tất cả các OR? Câu hỏi chân thành, tôi không hiểu.
ArturoTena

Trong SQL, phần còn lại của biểu thức được đánh giá theo cú pháp OR. Hãy thử điều này (nó sẽ không cho phép tôi bao gồm biểu tượng @ - bạn sẽ phải sửa nó nếu bạn muốn kiểm tra nó): khai báo var varchar (5) đặt var = '0' chọn 2 / var trong đó var <> 0 hoặc ISNUMERIC (var) = 1. Tôi muốn điều kiện thoát vì var IS bằng 0, nhưng nó sẽ đi trước để kiểm tra xem nó có phải là số không, và do đó, câu lệnh trả về lỗi.
tháng

điều này đã giúp trong trường hợp của tôi khi tôi có một toán tử so sánh khác nhau cho mỗi giá trị của loại.
Alex

vẫn tốt hơn DECLARE @locationType NVARCHAR(50) = 'youchoose' IF @locationType = 'location' BEGIN SELECT column1, column2 FROM viewWhatever WHERE (account_location = @locationID) END IF @locationType = 'area' BEGIN SELECT column1, column2 FROM viewWhatever WHERE (xxx_location_area = @locationID) END IF @locationType = 'division' BEGIN SELECT column1, column2 FROM viewWhatever WHERE (xxx_location_division = @locationID) END
Lukek

35

Bạn đi đây

SELECT
   column1, 
   column2
FROM
   viewWhatever
WHERE
CASE 
    WHEN @locationType = 'location' AND account_location = @locationID THEN 1
    WHEN @locationType = 'area' AND xxx_location_area = @locationID THEN 1
    WHEN @locationType = 'division' AND xxx_location_division = @locationID THEN 1
    ELSE 0
END = 1

5
Chà, tôi đã viết rằng đó là CHỌN cột1, cột2 TỪ viewWhthing WHERE (@locationType = 'location' AND account_location = @locationID) HOẶC (@locationType = 'area' AND xxx_location_area = @locationID) OR (@locationType = ' VÀ xxx_location_division = @locationID)
Jan de Vos

2
đây là một ví dụ rất an toàn, làm thế nào về kế hoạch thực hiện truy vấn với Trả lời tốt nhất (cá nhân tôi thích mã phương thức này rõ ràng và rõ ràng)
PEO

1
thực sự tuyệt vời nếu bạn muốn sử dụng mệnh đề where khác nhau với kiểu khác nhau như int trên mệnh đề 1 và nvarchar trên 2nd. với giải pháp Bob Probst không hoạt động. cảm ơn
Julian50

6

Tôi muốn nói rằng đây là một chỉ số về cấu trúc bảng thiếu sót. Có lẽ các loại vị trí khác nhau nên được phân tách trong các bảng khác nhau, cho phép bạn thực hiện truy vấn phong phú hơn nhiều và cũng tránh có các cột không cần thiết xung quanh.

Nếu bạn không thể thay đổi cấu trúc, một cái gì đó như dưới đây có thể hoạt động:

SELECT
    *
FROM
    Test
WHERE
    Account_Location = (
        CASE LocationType
          WHEN 'location' THEN @locationID
          ELSE Account_Location
        END
    )
    AND
    Account_Location_Area = (
        CASE LocationType
          WHEN 'area' THEN @locationID
          ELSE Account_Location_Area
        END
    )

Và cứ thế ... Chúng ta không thể thay đổi cấu trúc của truy vấn một cách nhanh chóng, nhưng chúng ta có thể ghi đè lên nó bằng cách làm cho các vị từ bằng nhau.

EDIT: Các đề xuất trên tất nhiên là tốt hơn nhiều, chỉ cần bỏ qua của tôi.


Tôi không nghĩ rằng đây là một cấu trúc bảng thiếu sót. Bảng được thiết lập theo cách này để nó tự tham chiếu để có số lượng quan hệ cha / con vô hạn. Hãy tin tôi, đó là mục đích. Tôi không nghĩ rằng tôi muốn thay đổi cấu trúc bảng của mình để chỉ sử dụng câu lệnh chuyển đổi. nó không quan trọng
Miles

5

Vấn đề với điều này là khi công cụ SQL đi đánh giá biểu thức, nó sẽ kiểm tra phần TỪ để kéo các bảng thích hợp và sau đó là phần WHERE để cung cấp một số tiêu chí cơ bản, do đó nó không thể đánh giá đúng một điều kiện động trên cột nào kiểm tra chống lại.

Bạn có thể sử dụng mệnh đề WHERE khi bạn kiểm tra tiêu chí WHERE trong vị ngữ, chẳng hạn như

WHERE account_location = CASE @locationType
                              WHEN 'business' THEN 45
                              WHEN 'area' THEN 52
                         END

vì vậy, trong trường hợp cụ thể của bạn, bạn sẽ cần đặt truy vấn vào một thủ tục được lưu trữ hoặc tạo ba truy vấn riêng biệt.


5

Toán tử OR có thể thay thế cho trường hợp khi ở điều kiện

ALTER PROCEDURE [dbo].[RPT_340bClinicDrugInventorySummary]
    -- Add the parameters for the stored procedure here
     @ClinicId BIGINT = 0,
     @selecttype int,
     @selectedValue varchar (50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT
    drugstock_drugname.n_cur_bal,drugname.cdrugname,clinic.cclinicname

FROM drugstock_drugname
INNER JOIN drugname ON drugstock_drugname.drugnameid_FK = drugname.drugnameid_PK
INNER JOIN drugstock_drugndc ON drugname.drugnameid_PK = drugstock_drugndc.drugnameid_FK
INNER JOIN drugndc ON drugstock_drugndc.drugndcid_FK = drugndc.drugid_PK
LEFT JOIN clinic ON drugstock_drugname.clinicid_FK = clinic.clinicid_PK

WHERE   (@ClinicId = 0 AND 1 = 1)
    OR  (@ClinicId != 0 AND drugstock_drugname.clinicid_FK = @ClinicId)

    -- Alternative Case When You can use OR
    AND ((@selecttype = 1 AND 1 = 1)
    OR  (@selecttype = 2 AND drugname.drugnameid_PK = @selectedValue)
    OR  (@selecttype = 3 AND drugndc.drugid_PK = @selectedValue)
    OR  (@selecttype = 4 AND drugname.cdrugclass = 'C2')
    OR  (@selecttype = 5 AND LEFT(drugname.cdrugclass, 1) = 'C'))

ORDER BY clinic.cclinicname, drugname.cdrugname
END

3

Vui lòng thử truy vấn này. Trả lời bài viết trên:

select @msgID, account_id
    from viewMailAccountsHeirachy
    where 
    CASE @smartLocationType
        WHEN 'store' THEN account_location
        WHEN 'area' THEN xxx_location_area 
        WHEN 'division' THEN xxx_location_division 
        WHEN 'company' THEN xxx_location_company 
    END  = @smartLocation

2
Đối với bất cứ ai đọc điều này trong tương lai: nó giống như câu trả lời được chấp nhận từ @ bob-prost ở trên: stackoverflow.com/a/206500/264786
ArturoTena

2

Thử cái này:

WHERE (
    @smartLocationType IS NULL 
    OR account_location = (
         CASE
            WHEN @smartLocationType IS NOT NULL 
                 THEN @smartLocationType
            ELSE account_location 
         END
    )
)

1
Bị từ chối vì tôi không hiểu làm thế nào điều này có thể chọn giữa các chuỗi đã cho (ví dụ: 'vị trí', 'khu vực', 'bộ phận')
ArturoTena

0
CREATE PROCEDURE [dbo].[Temp_Proc_Select_City]
    @StateId INT
AS  
        BEGIN       
            SELECT * FROM tbl_City 
                WHERE 
                @StateID = CASE WHEN ISNULL(@StateId,0) = 0 THEN 0 ELSE StateId END ORDER BY CityName
        END

-1
Case Statement in SQL Server Example

Syntax

CASE [ expression ]

   WHEN condition_1 THEN result_1
   WHEN condition_2 THEN result_2
   ...
   WHEN condition_n THEN result_n

   ELSE result

END

Example

SELECT contact_id,
CASE website_id
  WHEN 1 THEN 'TechOnTheNet.com'
  WHEN 2 THEN 'CheckYourMath.com'
  ELSE 'BigActivities.com'
END
FROM contacts;

OR

SELECT contact_id,
CASE
  WHEN website_id = 1 THEN 'TechOnTheNet.com'
  WHEN website_id = 2 THEN 'CheckYourMath.com'
  ELSE 'BigActivities.com'
END
FROM contacts;

4
Bị từ chối vì người trả lời này không liên quan đến câu hỏi. Câu hỏi là làm thế nào để sử dụng CASE trên mệnh đề WHERE, chứ không phải cách sử dụng CASE trên cột CHỌN.
ArturoTena

-2

Hãy thử truy vấn này. Rất dễ hiểu:

CREATE TABLE PersonsDetail(FirstName nvarchar(20), LastName nvarchar(20), GenderID int);
GO

INSERT INTO PersonsDetail VALUES(N'Gourav', N'Bhatia', 2),
              (N'Ramesh', N'Kumar', 1),
              (N'Ram', N'Lal', 2),
              (N'Sunil', N'Kumar', 3),
              (N'Sunny', N'Sehgal', 1),
              (N'Malkeet', N'Shaoul', 3),
              (N'Jassy', N'Sohal', 2);
GO

SELECT FirstName, LastName, Gender =
    CASE GenderID
    WHEN 1 THEN 'Male'
    WHEN 2 THEN 'Female'
    ELSE 'Unknown'
    END
FROM PersonsDetail

1
Đối với bất cứ ai đọc câu trả lời này: nó giống như câu trả lời được chấp nhận từ @ bob-prost ở trên: stackoverflow.com/a/206500/264786 Bị từ chối vì lý do này.
ArturoTena
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.