CEILING kullanılırken CASE ifadesi yanlış değer döndürüyor


11

Bir CASEifadenin beklediğim şeyi döndürmediği bir sorunla karşılaştım .

Bir test olarak, bir ondalık değişken ekledim CASEve ona karşı aynı ifadeyi çalıştırdım ve sonuçlar beklediğim gibi döndürerek iyi çalışıyor (değeri ne zaman yuvarlar IsGun=1. Ama aynı CASEifadeyi başka bir ondalık değere karşı çalıştırdığımda , her zaman CEILING()işlevli değer ve asla orijinal değeri döndürmez.

İşte SQL kodu:

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

İşte sonuçların bir pasajı:

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

İşte vProducts_PriceQty_Union'dan gelen veriler :

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

İlk beşten görebileceğiniz gibi, burada IsGun = 0, CASEsabit değişkeni kullanan ilk ifade , beklediğimiz gibi UsingVar değerini döndürür , 12.54. Ve son beş için 13 beklediğimiz değeri de döndürüyor.

Ancak ikinci CASEifadede (tam olarak aynı mantık), PriceAdj bu CEILINGişlevi IsGun = 1 olsun ya da olmasın , her birinde kullanır .

Sorgu neden beklenen sonuçları döndürmüyor?

Birliği için kullanılan tabloların bazıları için veri türlerini görünümünde Fiyat1 ve Price2 idi smallmoney ve ondalık (8,2) . O zamandan beri hepsini ondalık (8,2) olarak değiştirdim , ancak sonuçları etkilemedi.

Yanıtlar:


11

Sorunu yeniden oluşturmak için:

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;

Burada olan şu ki a CEILING(PQ.Price1Avg)üretir numeric(38, 0).

Dokümantasyona göre , çıktı türü CEILING()girişle aynı temel veri tipindedir , ancak ölçek (ondalık sayısı) değişebilir, burada olan şey budur.

  • AVG()Fonksiyon, benim testlerde, döner numeric(38, 6).
  • CEILING()Bu sütun üzerinde işlev Ancak çıkarır numeric(38, 0):

Doğrulamak için:

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

Geçici bir çözüm olarak, size CEILING()doğru sonuçları vermesi için işlevin çıktısını açıkça dönüştürebilirsiniz :

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;

Olgu ifadelerinin birden fazla farklı tür döndüremeyeceğini, ancak bir IIF ifadesinin geri döndürülebileceğini ve bu nedenle önerilebileceğini unutmayın.
Adam Martin

2
@AdamMartin doğru değil. Bir iifgenişletilir case. Bu büyük veri türü önceliği ile türünü döndürür iki seçenekten. Herhangi bir ifadenin bir satırda X veri türünü ve aynı sütun için başka bir satırdaki veri türünü Y döndürmesi mümkün değildir.
Martin Smith

@ Daniel, en yararlı. Her çıktı için CAST (x AS NUMERIC (8,2)) olur olmaz aradığım sonucu döndürdü. Size ve bu topluluğa çok teşekkürler!
Rodney G
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.