【问题标题】:How to design T-SQL query to calculate sum in one pass?如何设计 T-SQL 查询以一次性计算总和?
【发布时间】:2011-04-22 19:09:28
【问题描述】:

我正在尝试开发一个 T-SQL 查询,它将执行以下操作:

ROUND(100 * A / B, 1)

概念上很简单,但由于可能的 B=0 分母以及 A 和 B 变量,它很棘手。我期望的是像 93.2 这样的百分比值(以这种格式给出,没有 %)。甚至 932 也是可以接受的,因为我可以稍后转换它。

但是,我目前得到的是 151,这是记录数。

A = CASE WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN 1 ELSE 0 END
B = CASE WHEN [Date_Completed] IS NOT NULL THEN 1 ELSE 0 END

如果 B 不等于 0,我当前的逻辑只会将 A/B 相除。你能帮我解决这个问题吗? p.s.以上所有字段均来自同一个表 A。

我试过了:

SELECT CASE WHEN t.VarB<>0 THEN ROUND(100 * t.VarA / t.VarB, 1) 
ELSE 0 /* or whatever you'd want to return in this case */ 
END 
FROM (SELECT CASE WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN 1 
ELSE 0 
END AS VarA, 
CASE WHEN [Date_Completed] IS NOT NULL THEN 1 
ELSE 0 
END AS VarB 
FROM EXCEL.Batch_Records A) t

但是我返回了 33000 行,而不是只有一行,其中每行 = 100 或 0。

好主意,康拉德!我测试了您的解决方案,如果我只想要一个值,它就可以工作。但我没有告诉你的是,我需要从同一个查询中返回其他值。当我尝试添加其他值计算时,出现语法错误。所以这是我当前的查询。请问htis应该怎么改写?

select 
SUM(CASE WHEN A.DATE_RECEIVED IS NOT NULL THEN 1 ELSE 0 END) AS NUM_RECEIVED,
SUM(CASE WHEN [Date_Completed] IS NOT NULL THEN 1 ELSE 0 END) AS NUM_COMPLETE_OF_OPENED,
SUM(CASE WHEN A.DATE_COMPLETED IS NOT NULL THEN 1 ELSE 0 END) AS NUM_COMPLETED_IN_MONTH,
SUM(CASE WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN 1 ELSE 0 END) AS NUM_WITHOUT_ERROR,

round(100 * a/b , 1) 
from 
(select 
    sum(CASE  
        WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN  
            1.0  
        ELSE 0.0 END) A, 
    sum(CASE WHEN [Date_Completed] IS NOT NULL THEN 

1.0 ELSE 0.0 END) B 

FROM EXCEL.Batch_Records a 
LEFT JOIN EXCEL.QC_CODES d ON a.Part_Number = d.CODE_ID    
WHERE (a.[Group] = @GROUP or @GROUP = '' OR @GROUP IS NULL) AND A.Date_Received >= @STARTDATE AND A.Date_Received <= @ENDDATE

康拉德正确地告诉我#TEMP1 是一张空桌子。但现在我填充了它并在他的帮助下成功设计了这个查询:

SET @STARTDATE = '1/1/11'
SET @ENDDATE = '1/31/11'
SET @GROUP = 'INTERMEDIATES_FISH'
--SET @TABLE_TITLE = 'BATCH RECORD SUCCESS RATE'
--SET @DEPT = 'QC'     

IF EXISTS(SELECT * FROM TEMPDB.INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE '#TEMP1%')
DROP TABLE #TEMP1

--CREATE TABLE #TEMP1 (     MFG int ,      MFG2 int ,     QC int,      QC2 INT ,      [Group] NVARCHAR(MAX),     [Date_Completed] datetime,     Date_Received datetime)
SELECT
MFG, MFG2, QC, QC2, [GROUP], [DATE_COMPLETED], [DATE_RECEIVED]
INTO #TEMP1
FROM EXCEL.Batch_Records a 
WHERE (a.[Group] = @GROUP or @GROUP = '' OR @GROUP IS NULL) AND A.Date_Received >= @STARTDATE AND A.Date_Received <= @ENDDATE

------------------------------------------  
;WITH CTE AS 
( 
SELECT 
CASE 
WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN 
1.0 
ELSE 0.0 END A, 
CASE WHEN [Date_Completed] IS NOT NULL THEN 1.0 ELSE 0.0 END B, 
CASE WHEN A.Date_Received IS NOT NULL THEN 1 ELSE 0 END NUM_RECEIVED, 
CASE WHEN [Date_Completed] IS NOT NULL THEN 1 ELSE 0 END NUM_COMPLETE_OF_OPENED, 
CASE WHEN A.DATE_COMPLETED IS NOT NULL THEN 1 ELSE 0 END NUM_COMPLETED_IN_MONTH, 
CASE WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN 1 ELSE 0 END AS NUM_WITHOUT_ERROR 
FROM 
#TEMP1 a 
--WHERE (a.[Group] = @GROUP or @GROUP = '' OR @GROUP IS NULL) AND A.Date_Received >= @STARTDATE AND A.Date_Received <= @ENDDATE
) 

select 
round(100 * SUM(A)/SUM(b) , 1) , 
SUM(NUM_RECEIVED) NUM_RECEIVED, 
SUM(NUM_COMPLETE_OF_OPENED) NUM_COMPLETE_OF_OPENED, 
SUM(NUM_COMPLETED_IN_MONTH) NUM_COMPLETED_IN_MONTH, 
SUM(NUM_WITHOUT_ERROR) NUM_WITHOUT_ERROR 


FROM CTE 

【问题讨论】:

  • 您可以添加表架构吗?如果 t.VarA 和 t.VarB 的数据类型为 INT,它将返回 INT(从不给你小数)。问题:您是要汇总并仅返回 1 行,还是应该对每一行执行百分比计算?
  • 好吧,你有两个 From 子句,所以看起来不太好......试试这个从 Batch_Records 和 QC_CODES 中放入几行数据。然后把它写成你的输出应该是什么样子。
  • 总共只有 1 行(总结)。 MFG、MFG2、QC、QC2、Group 都是数据库中的 NVARCHAR(MAX)。 Date_completed 是日期时间。这能回答你的问题吗?
  • @Conrad,我刚刚从您下面的答案中复制了两个 FROM 语句。我误会你了吗?而且我不确定你对几行数据的意思。你的意思是你想看看这些值是什么样的,还是我需要填充数据?
  • @salvationishere 如果你看看这个question。 Eric H. 提供脚本来创建临时表并插入测试数据。然后他还包括预期的输出。这使人们更容易提供帮助。

标签: tsql


【解决方案1】:

基本上你需要使用 SUM() 来得到总和。您还应该使用 1.0 和 0.0 以便获得十进制值。

除法前你也应该做SUM

更新 由于您要添加许多 SUM(CASE 语句,因此将 CASE 语句移出 CTE 可能更具可读性。

CREATE TABLE #Batch_Records (
    MFG int , 
    MFG2 int ,
    QC int, 
    QC2 INT , 
    [Group] int,
    [Date_Completed] datetime,
    Date_Received datetime)




INSERT INTO #Batch_Records (MFG ,   MFG2 ,  QC ,    QC2  ,  [Group] ,   [Date_Completed] ,  Date_Received )
VALUES (1,null,null,null,1,'1/4/2011','2/4/2011'),
       (null,null,null,null,1,'2/2/2011','3/4/2011'),
       (1,null,null,null,1,'3/6/2011','4/3/2011'),
       (null,null,null,null,1,NULL,'5/4/2011'),
       (1,null,null,null,1,'5/4/2011','6/6/2011'),
       (1,null,null,null,1,NULL,'7/4/2011')


DECLARE @GROUP int
DECLARE @STARTDATE DateTime
DECLARE @ENDDATE DateTime

SET @GROUP = 1
SET @STARTDATE = '1/1/2001'
SET @ENDDATE = '1/1/2012'

;WITH CTE AS
(
    SELECT
        CASE  
            WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN  
                1.0  
            ELSE 0.0 END A, 
        CASE WHEN [Date_Completed] IS NOT NULL THEN 
        1.0 ELSE 0.0 END B,
        CASE WHEN A.Date_Received IS NOT NULL THEN 1 ELSE 0 END  NUM_RECEIVED,
        CASE WHEN [Date_Completed] IS NOT NULL THEN 1 ELSE 0 END  NUM_COMPLETE_OF_OPENED,   
        CASE WHEN A.DATE_COMPLETED IS NOT NULL THEN 1 ELSE 0 END  NUM_COMPLETED_IN_MONTH,
        CASE WHEN A.MFG IS NULL AND A.MFG2 IS NULL AND A.QC IS NULL AND A.QC2 IS NULL THEN 1 ELSE 0 END AS NUM_WITHOUT_ERROR
    FROM 
        #Batch_Records a 
    WHERE 
        (a.[Group] = @GROUP or @GROUP = '' OR @GROUP IS NULL) 
        AND A.Date_Received >= @STARTDATE AND A.Date_Received <= @ENDDATE
)

select 
    round(100 * SUM(A)/SUM(b) , 1) ,
    SUM(NUM_RECEIVED) NUM_RECEIVED,
    SUM(NUM_COMPLETE_OF_OPENED) NUM_COMPLETE_OF_OPENED,
    SUM(NUM_COMPLETED_IN_MONTH) NUM_COMPLETED_IN_MONTH,
    SUM(NUM_WITHOUT_ERROR) NUM_WITHOUT_ERROR


 FROM CTE

 DROP TABLE #Batch_Records

【讨论】:

  • 关于十进制值的好点。但是你能再看看吗?我正在更新我的问题。
  • 康拉德,您能否看看我上面的评论以回应您的评论?
  • 对不起,康拉德,您能再看一下我的查询吗?即使我复制了您的代码,它也会返回所有 NULL 值。
  • @salvationishere 你能用你使用的 SQL 更新你的问题吗?如果你完全按照我写的运行,它将返回 50.000000 6 4 4 2
  • 我几乎完全按照您写的内容运行,但它仍然返回所有 NULL。仅供参考,所有这些变量都是 VARCHAR,而不是 INT。所以我现在添加我使用的 SQL。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-01
  • 2021-10-02
  • 1970-01-01
  • 2021-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多