如何找出为啥所有数据子集的总和比总和小1

Posted

技术标签:

【中文标题】如何找出为啥所有数据子集的总和比总和小1【英文标题】:How to find why sum of all subsets of data is 1 less than total如何找出为什么所有数据子集的总和比总和小1 【发布时间】:2017-06-28 02:47:05 【问题描述】:

我有一些奖励数据。每个奖励或赠款都有一个赠款编号和金额以及实体的 ID。我按 ID 总结了奖励的计数和所有奖励的 $Amount。然后我根据范围检查返回一组总行或一个子集。

我怎样才能找出为什么所有子集的总和总是比总集小一?这是我的存储过程:

ALTER    Procedure [dbo].[FLAS2_List_Awards_V3_PrepAwards]
/* 
EXECUTE FLAS2_List_Awards_V3_PrepAwards 0
EXECUTE FLAS2_List_Awards_V3_PrepAwards 1
EXECUTE FLAS2_List_Awards_V3_PrepAwards 2
EXECUTE FLAS2_List_Awards_V3_PrepAwards 3
EXECUTE FLAS2_List_Awards_V3_PrepAwards 4
EXECUTE FLAS2_List_Awards_V3_PrepAwards 5
EXECUTE FLAS2_List_Awards_V3_PrepAwards 6
*/
-- populates #TempGrants according to range filter on TotalAmount
(
    @Range  int = 0
                    -- 0 = no filtering 
                    -- 1 = < $1 million
                    -- 2 = < $5 million
                    -- 3 = < $10 million
                    -- 4 = < $15 million
                    -- 5 = < $20 million
                    -- 6 = > $20 million
)
As
-- if calling sproc did not create this table, create here to allow unit testing
IF OBJECT_ID('tempdb..#TempGrants') IS NULL
BEGIN 
CREATE TABLE #TempGrants
(
    ID          nchar(6) NOT NULL
,   TotalAwards decimal (16, 0) NULL
,   TotalAmount decimal (16, 0) NULL
)
END
-- step 1. Summarize grants creating colums for HAVING filter
CREATE TABLE #TempGrantsUnfiltered
(
    ID          nchar(6) NOT NULL
,   TotalAwards decimal (16, 0) NULL
,   TotalAmount decimal (16, 0) NULL
)
insert into #TempGrantsUnfiltered
(
    ID          
,   TotalAwards 
,   TotalAmount 
)
select o.id
      ,COUNT( o.GrantNumber) as TotalAwards
      ,SUM( o.TotalObligatedAmount) as TotalAmount 
from dbo.FLAS2_Grants o
group BY O.ID
-- step 2. HAVING filter returns grant totals per range test
insert into #TempGrants
(
    ID          
,   TotalAwards 
,   TotalAmount 
)
select o.id
      ,TotalAwards
      ,TotalAmount 
from #TempGrantsUnfiltered o
WHERE
    CASE 
        When @Range = 0 Then 1  
        When @Range = 1 AND TotalAmount < 1000000 Then 1  
        When @Range = 2 AND TotalAmount BETWEEN  1000001  AND  5000000 Then 1  
        When @Range = 3 AND TotalAmount BETWEEN  5000001  AND 10000000 Then 1  
        When @Range = 4 AND TotalAmount BETWEEN 10000001  AND 15000000 Then 1  
        When @Range = 5 AND TotalAmount BETWEEN 15000001  AND 20000000 Then 1  
        When @Range = 6 AND TotalAmount > 20000000 Then 1  
        ELSE 0      -- where 0 = 1 rejects record
        END = 1     -- where 1 = 1 allows record
order by TotalAmount desc       

当我执行以下块时:

EXECUTE FLAS2_List_Awards_V3_PrepAwards 0
EXECUTE FLAS2_List_Awards_V3_PrepAwards 1
EXECUTE FLAS2_List_Awards_V3_PrepAwards 2
EXECUTE FLAS2_List_Awards_V3_PrepAwards 3
EXECUTE FLAS2_List_Awards_V3_PrepAwards 4
EXECUTE FLAS2_List_Awards_V3_PrepAwards 5
EXECUTE FLAS2_List_Awards_V3_PrepAwards 6

我在使用 SQL Management Studio 的消息窗口中得到以下结果:

(597 row(s) affected)

(597 row(s) affected)

(597 row(s) affected)

(65 row(s) affected)

(597 row(s) affected)

(341 row(s) affected)

(597 row(s) affected)

(89 row(s) affected)

(597 row(s) affected)

(39 row(s) affected)

(597 row(s) affected)

(23 row(s) affected)

(597 row(s) affected)

(39 row(s) affected)

我无法解释子集中缺少的行或总集中的额外行。有什么想法吗?

65 + 341 + 89 + 39 + 23 +39 = 596 < 597 

【问题讨论】:

不应该将TotalAmount &lt; 1000000 改为TotalAmount &lt;= 1000000TotalAmount &lt; 1000001 吗? 我同意 SqlZim - 如果您有一个 TotalAmount = 1000000 的奖项,那么这不会被任何过滤器拾取,但它会被未过滤的总数拾取。 【参考方案1】:

case 表达式中将 TotalAmount &lt; 1000000 更改为 TotalAmount &lt; 1000001

【讨论】:

非常感谢!我怀疑是一些愚蠢的错误,但就是看不到。 @JohnAdams 乐于助人! 小心点——我经常看到。人们没有明确指定他们希望在范围边界发生什么。存储过程中的 cmets 表示 @Range = 2 过滤 TotalAmount

以上是关于如何找出为啥所有数据子集的总和比总和小1的主要内容,如果未能解决你的问题,请参考以下文章

算法学习1863. 找出所有子集的异或总和再求和(java / c / c++ / python / go / rust)

算法学习1863. 找出所有子集的异或总和再求和(java / c / c++ / python / go / rust)

Leetcode5759. 找出所有子集的异或总和再求和(二进制模拟暴搜)

为啥我的子集总和方法不正确?

总和小于 M 的大小为 K 的子集的最大总和

如何递归枚举添加到给定总和的所有子集?