检查相等数量的负数作为正数

wor*_*ech 5 t-sql

我有一个包含两列的表:intGroupID,decAmount

我希望有一个查询,基本上可以返回intGroupID作为结果,如果对于每个正(+)decAmount,有一个相等和相反的负( - )decAmount.

因此,(id = 1,amount = 1.0),(1,2.0),(1,-1.0),(1,-2.0)的表将返回intGroupID为1,因为对于每个正数,都存在负数要匹配的数字.

到目前为止我所知道的是必须有相同数量的decAmounts(所以我强制执行count(*)%2 = 0)并且所有行的总和必须= 0.0.但是,通过该逻辑获得的一些案例是:

ID | 量

  • 1 | 1.0
  • 1 | -1.0
  • 1 | 2.0
  • 1 | -2.0
  • 1 | 3.0
  • 1 | 2.0
  • 1 | -4.0
  • 1 | -1.0

它的总和为0.0并且行数为偶数,但是正数与负数之间没有1对1的关系.我需要一个查询,基本上可以告诉我每个正数量是否有负数,而不重用任何行.

我尝试计算数字的不同绝对值,并强制它小于所有行的计数,但它没有捕获所有内容.

我到目前为止的代码:

    DECLARE @tblTest TABLE(
    intGroupID INT
    ,decAmount DECIMAL(19,2)
);

INSERT INTO @tblTest (intGroupID ,decAmount)
VALUES (1,-1.0),(1,1.0),(1,2.0),(1,-2.0),(1,3.0),(1,2.0),(1,-4.0),(1,-1.0);

DECLARE @intABSCount INT = 0
    ,@intFullCount INT = 0;

SELECT @intFullCount = COUNT(*) FROM @tblTest;

SELECT @intABSCount = COUNT(*) FROM (
SELECT DISTINCT ABS(decAmount) AS absCount FROM @tblTest GROUP BY ABS(decAmount)
) AS absCount

SELECT t1.intGroupID
FROM @tblTest AS t1

    /* Make Sure Even Number Of Rows */
    INNER JOIN
    (SELECT COUNT(*) AS intCount FROM @tblTest 
    )
    AS t2 ON t2.intCount % 2 = 0

    /* Make Sure Sum = 0.0 */
    INNER JOIN
    (SELECT SUM(decAmount) AS decSum FROM @tblTest)
    AS t3 ON decSum = 0.0

/* Make Sure Count of Absolute Values < Count of Values */
WHERE 
    @intABSCount < @intFullCount
GROUP BY t1.intGroupID
Run Code Online (Sandbox Code Playgroud)

我认为可能有更好的方法来检查这个表,可能是通过查找对并从表中删除它们,看看一旦没有更多的正/负匹配,表中是否还有任何东西,但我宁愿不必使用递归/游标.

Dan*_*nez 0

天哪,我找到了比之前的答案更简单的方法。我希望我所有疯狂的编辑都能被保存下来供后代使用。

  • 这是通过按绝对值对 id 的所有数字进行分组(1、-1 按 1 分组)来实现的。
  • 组的总和决定是否有相同数量的对。如果为 0,则相等,任何其他值的总和都意味着存在不平衡。
  • COUNT仅当检测偶数个零时才需要通过聚合来检测均匀度。我假设 0 可能存在,并且它们应该出现偶数次。如果这不是问题,请将其删除,因为 0 始终会通过第一个测试。
  • 我用多种不同的方式重写了查询以获得最佳执行计划。下面的最终结果只有一个大堆排序,由于缺乏索引,这是不可避免的。

询问

WITH tt AS (
    SELECT intGroupID, 
        CASE WHEN SUM(decAmount) > 0 OR COUNT(*) % 2 = 1 THEN 1 ELSE 0 END unequal
    FROM @tblTest 
    GROUP BY intGroupID, ABS(decAmount)
)
SELECT tt.intGroupID, 
    CASE WHEN SUM(unequal) != 0 THEN 'not equal' ELSE 'equals' END [pair]
FROM tt
GROUP BY intGroupID;
Run Code Online (Sandbox Code Playgroud)

测试值

(1,-1.0),(1,1.0),(1,2),(1,-2), -- should work
(2,-1.0),(2,1.0),(2,2),(2,2), -- fail, two positive twos
(3,1.0),(3,1.0),(3,-1.0), -- fail two 1's , one -1
(4,1),(4,2),(4,-.5),(4,-2.5), -- fail: adds up the same sum, but different values
(5,1),(5,-1),(5,0),(5,0), -- work, test zeros
(6,1),(6,-1),(6,0), -- fail, test zeros
(7,1),(7,-1),(7,-1),(7,1),(7,1) -- fail, 3 x 1
Run Code Online (Sandbox Code Playgroud)

结果

A   pairs
_   _____
1   equal
2   not equal
3   not equal
4   not equal
5   equal
6   not equal
7   not equal
Run Code Online (Sandbox Code Playgroud)