J'ai rencontré un problème dans lequel une expression CASE
ne renvoie pas ce que j'attends.
En tant que test, j'ai ajouté un Decimal variable et couru la même chose CASE
expression contre elle et cela fonctionne bien, renvoyant les résultats comme je m'attends (arrondir la valeur lorsque IsGun=1
. Mais quand j'exécute la même chose CASE
expression contre une autre valeur décimale, elle renvoie toujours la valeur avec la fonction CEILING()
et ne renvoie jamais la valeur d'origine.
Voici le code 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
Voici un extrait des résultats:
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
Et voici les données qu'il vient de 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
Comme vous pouvez le voir à partir des cinq premiers, où isgun = 0, la première CASE
expression à l'aide de la variable fixe renvoie le Utilisation devar valeur Ce que nous attendions, 12.54. Et pour les cinq derniers, cela renvoie également la valeur que nous attendrions, 13.
Mais dans la seconde CASE
expression (exactement la même logique), le priséadj utilise la fonction CEILING
sur chacun d'entre eux, que ce soit Isgun = 1 ou non.
Pourquoi la requête ne renvoie-t-elle pas les résultats attendus?
Dans certaines des tables utilisées pour l'Union, voir les types de données pour Prix1 et Prix2 était SmallMoney et Decimal (8,2). Depuis, je leur ai changé tous pour être décimal (8,2), mais cela n'a pas affecté les résultats.
Pour reproduire le problème:
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;
Ce qui se passe ici, c'est que CEILING(PQ.Price1Avg)
produit un numeric(38, 0)
.
Selon la - Documentation , le type de sortie de CEILING()
est du même type de données de base que l'entrée, bien que l'échelle (le nombre de décimales) puisse changer, ce qui se passe ici .
AVG()
, dans mes tests, retourne numeric(38, 6)
.CEILING()
fonctionne sur cette colonne, cependant, sorties numeric(38, 0)
:Vérifier:
SELECT CEILING(CAST(123.45 AS numeric(38, 6)))
En tant que solution de contournement, vous pouvez convertir explicitement la sortie de la fonction CEILING()
, qui devrait vous donner les résultats corrects:
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;