从SQL / JAVA计算百分比的最佳方法

时间:2014-07-14 07:10:15

标签: java sql sql-server sql-server-2008 stored-procedures

我的查询如下:

SELECT  dbo.tablename.part_number,
        DATEPART(year, dbo.tablename_test.test_date_time) as year,
        DATEPART(month, dbo.tablename_test.test_date_time) as month,
        COUNT(dbo.tablename_test.overall_pass) AS Count,
        dbo.tablename_test.overall_pass 
FROM dbo.tablename_test 
    INNER JOIN dbo.tablename 
        ON dbo.tablename_test.tablename_id = dbo.tablename.tablename_id 
WHERE dbo.tablename_test.test_date_time BETWEEN '2003-01-01' AND '2013-06-01' 
AND (dbo.tablename_test.resolution_code IS NULL 
    OR dbo.tablename_test.resolution_code = 'None') 
AND dbo.tablename_test.operator IN ('Arlene Haselhorst','Trang Luong','Elena Viloria')
GROUP BY DATEPART(year, dbo.tablename_test.test_date_time),
         DATEPART(month, dbo.tablename_test.test_date_time),
         dbo.tablename.part_number,
         dbo.tablename_test.overall_pass 
ORDER BY  DATEPART(year, dbo.tablename_test.test_date_time),
          dbo.tablename.part_number,
          dbo.tablename_test.overall_pass

此查询的输出为:

#   part_number year    month   count   overall_pass
#1  700-0376    2003    8        2        0
#2  700-0376    2003    11       1        0
#3  700-0376    2003    8        59       1
#4  700-0376    2003    10       34       1
#5  700-0376    2003    11       63       1
#6  700-0376    2004    2        12       0
#7  700-0376    2004    3         3       0
#8  700-0376    2004    5        13       0
#9  700-0376    2004    7        5        0
#10 700-0376    2004    11       3        0
#11 700-0376    2004    2       139       1
#12 700-0376    2004    3       150       1
#13 700-0376    2004    5       287       1
#.    .            .     .       .        .
#.    .            .     .       .        .

结果只显示一个数字的数据。有多个partnumber。 我需要找到每个partnumber,year,month

的总传递值的百分比

我如何在SQL中执行此操作。在JAVA中执行此操作的最佳方法是什么。我需要有以下数据:

partnumber year month overallpass percentage
700-0376   2003  8      1          95.72
700-0376   2003  11     1          98.43
700-0376   2003  10     1          100.00
700-0376   2004  2      1          92.05
 .           .    .     .            .
 .           .    .     .            .

百分比计算为计数值(59)/61(59+2)*100=95.72。我需要为同年和月份的所有部分编号执行此操作。

我必须从数据库中获取数据并使用谷歌图表将其绘制在图表上。对此最好的方法是什么?

2 个答案:

答案 0 :(得分:0)

如果我已经将问题解释为OK,那么在计数传递时你需要在计数内部使用一个case表达式(例如得到59)但是对于除数不能这样做(得到61)并且你不希望整个传递

分组
SELECT
      dbo.tablename.part_number
    , DATEPART(YEAR, dbo.tablename_test.test_date_time)                          AS year
    , DATEPART(MONTH, dbo.tablename_test.test_date_time)                         AS month
    , COUNT(CASE WHEN overall_pass = 1 THEN dbo.tablename_test.overall_pass END) AS Count_Passes
    , COUNT(dbo.tablename_test.overall_pass)                                     AS Count_All
    , COUNT(CASE WHEN overall_pass = 1 THEN dbo.tablename_test.overall_pass END)
      / COUNT(dbo.tablename_test.overall_pass)                                   AS Count_Percent
FROM dbo.tablename_test
      INNER JOIN dbo.tablename
                  ON dbo.tablename_test.tablename_id = dbo.tablename.tablename_id
WHERE dbo.tablename_test.test_date_time BETWEEN '2003-01-01' AND '2013-06-01'
      AND (dbo.tablename_test.resolution_code IS NULL
      OR dbo.tablename_test.resolution_code = 'None')
      AND dbo.tablename_test.operator IN ('Arlene Haselhorst', 'Trang Luong', 'Elena Viloria')
GROUP BY
      DATEPART(YEAR, dbo.tablename_test.test_date_time)
    , DATEPART(MONTH, dbo.tablename_test.test_date_time)
    , dbo.tablename.part_number
ORDER BY
      dbo.tablename.part_number
      , DATEPART(YEAR, dbo.tablename_test.test_date_time)
      , DATEPART(MONTH, dbo.tablename_test.test_date_time)

答案 1 :(得分:0)

首先,如果在SQL中处理日期/时间/时间戳,您不应该使用inclusive upper bound of BETWEEN with positive contiguous-range types(其中日期/时间/时间戳是子集),尤其是服务器。就目前而言,你只是在六月的第一天(去年),我觉得很可疑。

此外,在表内数据中使用函数将使索引的使用无效,从而使对大型结果集的查询变慢。你想要一个范围表,看起来像这样:

range_start    range_end     year   month
==========================================
'2003-01-01'   '2003-02-01'  2003   1
'2003-02-01'   '2003-03-01'  2003   2
..............
'2013-05-01'   '2013-06-01'  2013   5

如果您有日历表,则应该可以在那里使用数据。否则,您可以使用递归CTE轻松生成一个:

WITH Calendar_Range AS (SELECT d AS range_start, DATEADD(month, 1, d) AS range_end,
                               DATEPART(year, d) AS year, DATEPART(month, d) AS month
                        FROM (VALUES(CAST('20030101' AS DATE))) t(d)
                        UNION ALL
                        SELECT range_end AS range_start, DATEADD(month, 1, range_end) AS range_end,
                               DATEPART(year, range_end) AS year, DATEPART(month, range_end) AS month
                        FROM Calendar_Range
                        WHERE range_end < CAST('20130601' AS DATE))

SQL Fiddle Demonstration

现在,COUNT(*)COUNT(<expression>)之间的区别是什么?后者(第二个)将忽略(不计数)空行。我们可以使用简单的连接条件来计算行数...类似于以下

SELECT COUNT(p.didPass)
FROM tablename_test
LEFT JOIN (VALUES(1)) p(didPass)
       ON p.didPass = tablename_test.overall_pass

...这基本上等同于CASE - 计算行数(尽管优化程序可以能够更好地优化此行)

结果查询可能如下所示:

WITH Calendar_Range AS (SELECT d AS range_start, DATEADD(month, 1, d) AS range_end,
                               DATEPART(year, d) AS year, DATEPART(month, d) AS month
                        FROM (VALUES(CAST('20030101' AS DATE))) t(d)
                        UNION ALL
                        SELECT range_end AS range_start, DATEADD(month, 1, range_end) AS range_end,
                               DATEPART(year, range_end) AS year, DATEPART(month, range_end) AS month
                        FROM Calendar_Range
                        WHERE range_end < CAST('20130601' AS DATE))

SELECT Calendar_Range.year, Calendar_Range.month, Part.part_number, 
       100.0 * COUNT(Pass.didPass) / COUNT(*) AS percentage
FROM dbo.tablename Part
JOIN dbo.tablename_test Test
  ON Test.tablename_id = Part.tablename_id
     AND Test.operator IN('Arlene Haselhorst','Trang Luong','Elena Viloria')
     AND (Test.resolution_code IS NULL OR Test.resolution_code = 'None')
JOIN Calendar_Range
  ON Test.test_date_time >= Calendar_Range.range_start
     AND Test.test_date_time < Calendar_Range.range_end
LEFT JOIN (VALUES(1)) Pass(didPass)
       ON Pass.didPass = Test.overall_pass
GROUP BY Calendar_Range.year, Calendar_Range.month, Part.part_number
ORDER BY Calendar_Range.year, Calendar_Range.month, Part.part_number

(未经测试,因为未提供样本起始数据)

我从最终结果集中删除了overall_pass,因为常量列并没有真正告诉你任何事情(当值已知时)。为了避免混淆,我将SELECT中的列顺序与ORDER BY进行了匹配(我还切换了GROUP BY中的列,但这实际上并没有改变结果)。我调整了操作的顺序,并使用浮点值来计算percentage,或者你最终会得到整数除法(即获得1000,但不是介于两者之间的任何事情。)