'where'절의 SQL 스위치 / 케이스


146

나는 주변을 둘러 보려고했지만 나를 도울만한 것을 찾을 수 없었다.

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

각 끝에 끝에 '= @locationID'를 넣을 필요는 없지만 구문이 정확하다는 것을 알 수는 없습니다. SQL은 첫 번째 줄에서 내 '='에 대해 계속 불평합니다 ...

어떻게해야합니까?

답변:


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
TomH가 아래 회신에 대한 주석에서 언급 한 것처럼 SQL을 잘못 구성했습니다. SQLServer 2005에서 테스트했으며 제대로 작동했습니다.
Bob Probst 2018 년

@가 필요한 이유는 무엇입니까? 그들은 무엇을합니까?
Tadej

2
@는 @가없는 t-sql의 변수를 나타내며 @locationID는 열 이름으로 해석됩니다.
Christian Sloper 2016 년

70

사례 진술없이 ...

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
조건 후 Case 문 종료이 충족 이것은 약간 다른 결과를 줄 것입니다 -하지만 OR 구문은 모든 가능성을 평가합니다
tember

1
@tember SQL이 절차 언어 인 경우에도 첫 번째 OR이 true이면 나머지 표현식은 평가되지 않습니다. SQL은 선언적 언어이므로 DBM이 모든 OR을 평가한다는 것을 어떻게 알 수 있습니까? 진지한 질문, 나는 이해하지 못한다.
ArturoTena 2016 년

SQL에서 나머지 표현식은 OR 구문으로 평가됩니다. 이것을 시도하십시오 (@ 기호를 포함시키지 않을 것입니다-테스트하려면 수정해야합니다) : var varchar (5) set var = '0'select 2 / var where var <> 0 또는 ISNUMERIC (var) = 1입니다. var IS가 0이기 때문에 조건을 끝내고 싶지만 숫자인지 확인하기 위해 계속 진행하므로 문이 오류를 반환합니다.

이것은 유형의 각 값에 대해 다른 비교 연산자가있는 경우 도움이되었습니다.
Alex

더 나은 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

여기 요

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
글쎄, SELECT column1, column2 FROM viewWHERE (@locationType = 'location'AND account_location = @locationID) OR (@locationType = 'area'AND xxx_location_area = @locationID) OR (@locationType = 'division' AND xxx_location_division = @locationID)
Jan de Vos

2
이것은 가장 좋은 예입니다. 최고의 답변을 얻은 쿼리 실행 계획은 어떻습니까 (개인적 으로이 방법 코드는 명확하고 깨끗합니다)
PEO

1
첫 번째 절의 int와 두 번째의 nvarchar와 같은 다른 유형의 다른 where 절을 사용하려면 정말 좋습니다. Bob Probst 솔루션이 작동하지 않습니다. 감사합니다
Julian50

6

나는 이것이 결함이있는 테이블 구조의 지표라고 말하고 싶다. 다른 위치 유형을 다른 테이블로 분리해야하므로 훨씬 더 풍부한 쿼리를 수행하고 불필요한 열을 피할 수 있습니다.

구조를 변경할 수 없으면 다음과 같이 작동 할 수 있습니다.

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
    )

그리고 등등 ... 우리는 쿼리의 구조를 즉석에서 바꿀 수 없지만, 술어 자체를 동일하게 만들어서 그것을 무시할 수 있습니다.

편집 : 위의 제안은 물론 훨씬 낫습니다. 내 것을 무시하십시오.


나는 이것이 결함이있는 테이블 구조라고 생각하지 않습니다. 테이블은 이러한 방식으로 설정되어 무한한 양의 부모 / 자식 관계를 갖는 자체 참조가되었습니다. 나를 믿으십시오. 그것은 의도적이었습니다. switch 문만 사용하도록 테이블 구조를 변경하고 싶지는 않습니다. 그 중요한 점
마일 :

5

이것의 문제점은 SQL 엔진이 표현식을 평가할 때 적절한 테이블을 가져 오기 위해 FROM 부분을 확인한 다음 일부 기준을 제공하기 위해 WHERE 부분을 확인하여 열이 어떤 동적 조건을 올바르게 평가할 수 없다는 것입니다 확인하십시오.

술어에서 WHERE 기준을 확인할 때 WHERE 절을 사용할 수 있습니다.

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

따라서 특별한 경우 쿼리를 저장 프로 시저에 넣거나 세 개의 별도 쿼리를 만들어야합니다.


5

OR 연산자는 조건에 따라 대용 할 수 있습니다.

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

이 쿼리를 시도하십시오. 위의 게시물에 답변 :

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
미래에 이것을 읽는 사람
에게는

2

이 시도:

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

1
주어진 문자열 (예 : 'location', 'area', 'division') 중에서 선택할 수있는 방법을 이해하지 못했기 때문에 하향식
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
이 답변은 질문과 관련이 없기 때문에 하향 투표되었습니다. 문제는 SELECTed 열에서 CASE를 사용하는 방법이 아니라 WHERE 절에서 CASE를 사용하는 방법이었습니다.
ArturoTena 2016 년

-2

이 쿼리를 시도하십시오. 이해하기 매우 쉽습니다.

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
이 답변을 읽는 사람 에게는 위의 @ bob-prost에서 받아 들인 답변과 동일합니다. stackoverflow.com/a/206500/264786 이러한 이유로 Downvoted.
ArturoTena 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.