CEILING을 사용할 때 CASE 표현식이 잘못된 값을 리턴 함


11

CASE식이 기대 한 것을 반환하지 않는 문제가 발생했습니다 .

시험 삼아, 나는 추가 소수점 변수를 같은 실행 CASE반대 표현을 내가 값을 때 반올림 (예상대로 결과를 반환 잘 작동합니다 IsGun=1.하지만 같은 실행 CASE다른 진수 값과 식을, 그것은 항상 반환 CEILING()함수 가 포함 된 값이며 원래 값을 반환하지 않습니다.

다음은 SQL 코드입니다.

DECLARE @Num decimal(8,2);
    set @Num = 12.54;
    WITH PQ AS
    ( 
        SELECT 
            UPC, 
            Price1, 
            DBID,
            AVG(Price1) OVER (PARTITION BY UPC) AS Price1Avg
        FROM
            vProducts_PriceQty_Union
    )
    SELECT 
        PQ.UPC,
        PQ.Price1,
        PQ.Price1Avg,
        (CASE WHEN p.IsGun = 1 THEN CEILING(@Num) ELSE @Num END) AS UsingVar,
        CAST(
            (CASE WHEN P.IsGun = 1 THEN CEILING(PQ.Price1Avg) ELSE PQ.Price1 END)
             AS NUMERIC(8,2))
        AS PriceAdj,
        PQ.DBID,
        P.IsGun
    FROM
        PQ
     INNER JOIN
        products P ON PQ.UPC = P.UPC

다음은 결과 스 니펫입니다.

UPC             Price1      Price1Avg   UsingVar    PriceAdj    DBID  IsGun
942000899195    14.9900     14.990000   12.54       15.00       1       0
980420671300    29.9900     29.990000   12.54       30.00       1       0
980420671310    29.9900     29.990000   12.54       30.00       1       0
980426713020    29.9900     29.990000   12.54       30.00       1       0
980426713120    29.9900     29.990000   12.54       30.00       1       0
000998622130    319.0000    319.000000  13.00       319.00      1       1
000998624730    314.0000    314.000000  13.00       314.00      1       1
000998624970    419.0000    419.000000  13.00       419.00      1       1
008244284754    1015.0000   1015.000000 13.00       1015.00     2       1
010633012288    267.0000    267.000000  13.00       267.00      6       1

다음은 vProducts_PriceQty_Union 에서 가져온 데이터입니다 .

UPC             Price1  Price2  Quantity    DBID
942000899195    14.9900 0.0000  2.00        1
980420671300    29.9900 0.0000  3.00        1
980420671310    29.9900 0.0000  1.00        1
980426713020    29.9900 0.0000  2.00        1
980426713120    29.9900 0.0000  1.00        1

처음 다섯 개에서 알 수 있듯이 IsGun = 0 인 CASE경우 고정 변수를 사용하는 첫 번째 표현식은 UsingVar 값을 예상대로 12.54로 반환합니다 . 그리고 마지막 5 개의 경우 예상 값인 13도 반환합니다.

그러나 두 번째 CASE표현식 (정확히 동일한 논리)에서 PriceAdjIsGun = 1 CEILING인지 여부에 관계없이 모든 단일 함수에서 함수를 사용합니다 .

쿼리가 예상 결과를 반환하지 않는 이유는 무엇입니까?

통합 뷰에 사용 된 일부 테이블에서 Price1Price2 의 데이터 유형 은 smallmoneydecimal (8,2) 입니다. 이후에 그것들을 모두 decimal (8,2) 로 변경했지만 결과에는 영향을 미치지 않았습니다.

답변:


11

문제를 재현하려면

SELECT *, (CASE
    WHEN IsGun=1 THEN CEILING(Price1Avg)
    ELSE Price1 END)
FROM (
    SELECT UPC, IsGun, Price1,
           AVG(CAST(Price1 AS numeric(8, 2))) OVER (PARTITION BY UPC) AS Price1Avg
    FROM (
        VALUES ('A', 0, 14.99),
               ('B', 0, 29.99),
               ('C', 1, 319.00),
               ('D', 1, 314.00)
        ) AS x(UPC, IsGun, Price1)
    ) AS sub;

여기에서 발생하는 즉 CEILING(PQ.Price1Avg)생산 numeric(38, 0).

documentation 에 따르면 , 출력 유형은 입력과 CEILING()동일한 기본 데이터 유형이지만 스케일 (소수)이 변경 될 수 있지만 여기서 발생합니다.

  • AVG()기능은, 내 테스트에서 반환합니다 numeric(38, 6).
  • CEILING()그 열에 기능하지만, 출력 numeric(38, 0):

확인하려면 :

SELECT CEILING(CAST(123.45 AS numeric(38, 6)))

이 문제를 해결하려면 CEILING()함수 의 출력을 명시 적으로 변환 하면 올바른 결과를 얻을 수 있습니다.

SELECT *, (CASE
    WHEN IsGun=1 THEN CAST(CEILING(Price1Avg) AS numeric(8, 2)) -- Explicit CAST.
    ELSE Price1 END)
FROM (
    SELECT UPC, IsGun, Price1,
           AVG(CAST(Price1 AS numeric(8, 2))) OVER (PARTITION BY UPC) AS Price1Avg
    FROM (
        VALUES ('A', 0, 14.99),
               ('B', 0, 29.99),
               ('C', 1, 319.00),
               ('D', 1, 314.00)
        ) AS x(UPC, IsGun, Price1)
    ) AS sub;

또한 case 문은 여러 다른 유형을 반환 할 수 없지만 IIF 식은 반환 할 수 있으므로 권장 할 수 있습니다.
Adam Martin

2
@AdamMartin 맞지 않습니다. 로 iif확장되었습니다 case. 그것은 가장 큰 데이터 형식 우선 순위 유형 돌려 두 가지 옵션에서합니다. 어떤 식으로도 한 열에 데이터 유형 X를, 같은 열에 대해 다른 행에 데이터 유형 Y를 반환 할 수 없습니다.
Martin Smith

@Daniel, 가장 도움이되었습니다. 각 출력에 대해 I CAST (x AS NUMERIC (8,2))를 보자 마자 찾고 있던 결과를 반환했습니다. 이 커뮤니티와 많은 분들께 감사드립니다!
Rodney G
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.