在SQL Server CASE中对负值进行分组

时间:2012-07-12 22:37:14

标签: sql-server case

我正在尝试将CASE语句中的值组合在一起SQL Server。当值为正时,它可以正常工作。当值为负时,它会爆炸。

Here's a link to the SQL Fiddle I created to replicate it:

以下是代码:

    -- Create the table --

    CREATE TABLE Test (
        ClientID varchar(12),
        Value decimal(12,10)
      PRIMARY KEY (ClientID)
      );


    -- Load the data -- 
    INSERT INTO Test (ClientId, Value)
            VALUES('1','10'),
            ('2','-10'),
            ('3','11.2'),
            ('4','-11.6'),
            ('5','12.544'),
            ('6','-13.456'),
            ('7','14.04928'),
            ('8','-15.6089'),
            ('9','15.7351'),
            ('10','-18.1063'),
            ('11','17.6234'),
            ('12','-21.0034'),
            ('13','19.7382'),
            ('14','-24.3639'),
            ('15','22.1068'),
            ('16','-28.2621'),
            ('17','24.7596'),
            ('18','-32.7841'),
            ('19','27.7307'),
            ('20','-38.0296'),
            ('21','31.0584'),
            ('22','-44.1141'),
            ('23','34.785499'),
            ('24','-51.1726'),
            ('25','38.9597'),
            ('26','-59.3602'),
            ('27','43.6349'),
            ('28','-68.8579'),
            ('29','48.8711'),
            ('30','-79.8751');

现在运行CASE语句:

SELECT 
  CASE
    WHEN Value BETWEEN 0 AND 20 THEN '0-20'
    WHEN Value BETWEEN 21 AND 40 THEN '20-40'
    ELSE '40+'
    END as ValueRange, count(*) as count
FROM Test
WHERE Value > 0
GROUP BY CASE
  WHEN Value BETWEEN 0 AND 20 THEN '0-20'
  WHEN Value BETWEEN 21 AND 40 THEN '20-40'
  ELSE '40+'
  END
;

工作正常。结果:

VALUERANGE      count
0-20           7
20-40          6
40+            2

现在有负值 - 它不起作用:

SELECT 
  CASE
    WHEN Value BETWEEN 0 AND -20 THEN '0-20'
    WHEN Value BETWEEN -21 AND -40 THEN '20-40'
    ELSE '40+'
    END
 as ValueRange, count(*) as count
FROM Test
WHERE Value < 0
GROUP BY CASE
  WHEN Value BETWEEN 0 AND -20 THEN '0-20'
  WHEN Value BETWEEN -21 AND -40 THEN '20-40'
  ELSE '40+'
  END
;

结果:

VALUERANGE  count
40+          15

它将每个人分组为40+ - 不分解较低的值范围。

谁能看到我做错了什么?

2 个答案:

答案 0 :(得分:3)

尝试

SELECT 
  CASE
    WHEN Value BETWEEN -20 AND 0 THEN '0-20'
    WHEN Value BETWEEN -40 AND -21 THEN '20-40'
ELSE '40+'
END
 as ValueRange, count(*)
FROM Test
--WHERE Value > 0
GROUP BY CASE
  WHEN Value BETWEEN -20 AND 0 THEN '0-20'
  WHEN Value BETWEEN -40 AND -21 THEN '20-40'
  ELSE '40+'
END
;

我希望介于最小值之间。

ValueRange 
---------- -----------
0-20       5
20-40      5
40+        20

答案 1 :(得分:3)

你的问题已经解决了(把负数放在首位,所以BETWEEN值按升序排列)但你可能希望看到一些替代查询语法(我更喜欢CASE结构):

SELECT 
   ValueRange =
      Convert(varchar(11), R.Low)
      + Coalesce(' - ' + Convert(varchar(11), R.High - 1), '+'),
   Qty = Count(*)
FROM
   dbo.Test T
   INNER JOIN (
      SELECT 0, 21
      UNION ALL SELECT 21, 41
      UNION ALL SELECT 41, NULL
   ) R (Low, High)
      ON T.Value >= R.Low
      AND T.Value < Coalesce(R.High, 2147483647)
WHERE T.Value >= 0
GROUP BY R.Low, R.High;

我更喜欢这个,因为我发现修改范围值比使用case语句更容易,而且有助于避免重复文本描述中的数字。

如果你只想要一个块中的每20个,那么这更容易:

SELECT
   BlockHigh = (Value + 19) / 20 * 20, -- 20 for 1-20, 40 for 21 - 40, etc.
   Qty = Count(*)
FROM dbo.Test
GROUP BY (Value + 19) / 20 * 20;

我假设在第一个查询中你可能没有使用整数,而在第二个查询中你是。

请注意,您的“40+”是错误的,因为它与您编写CASE语句的方式实际上是“41+”。