我有一个包含两列的表: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 |量
它的总和为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
我认为可能有更好的方法来检查这个表,可能是通过查找对并从表中删除它们,看看一旦没有更多的正/负匹配,表中是否还有任何东西,但我宁愿不必使用递归/游标。
答案 0 :(得分:1)
Create TABLE #tblTest (
intA INT
,decA DECIMAL(19,2)
);
INSERT INTO #tblTest (intA,decA)
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), (5,-5.0),(5,5.0) ;
SELECT * FROM #tblTest;
SELECT
intA
, MIN(Result) as IsBalanced
FROM
(
SELECT intA, X,Result =
CASE
WHEN count(*)%2 = 0 THEN 1
ELSE 0
END
FROM
(
---- Start thinking here --- inside-out
SELECT
intA
, x =
CASE
WHEN decA < 0 THEN
-1 * decA
ELSE
decA
END
FROM #tblTest
) t1
Group by intA, X
)t2
GROUP BY intA
答案 1 :(得分:1)
未经测试但我认为你可以得到这个想法
这将返回不符合的id 不容易测试/调试
select pos.*, neg.*
from
( select id, amount, count(*) as ccount
from tbl
where amount > 0
group by id, amount ) pos
full outer join
( select id, amount, count(*) as ccount
from tbl
where amount < 0
group by id, amount ) neg
on pos.id = neg.id
and pos.amount = -neg.amount
and pos.ccount = neg.ccount
where pos.id is null
or neg.id is null
I think this will return a list of id that do conform
select distinct(id) from tbl
except
select distinct(isnull(pos.id, neg.id))
from
( select id, amount, count(*) as ccount
from tbl
where amount > 0
group by id, amount ) pos
full outer join
( select id, amount, count(*) as ccount
from tbl
where amount < 0
group by id, amount ) neg
on pos.id = neg.id
and pos.amount = -neg.amount
and pos.ccount = neg.ccount
where pos.id is null
or neg.id is null
答案 2 :(得分: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;
经过测试的值
(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
<强>结果
A pairs
_ _____
1 equal
2 not equal
3 not equal
4 not equal
5 equal
6 not equal
7 not equal
答案 3 :(得分:0)
这有帮助吗?
-- Expected result - group 1 and 3
declare @matches table (groupid int, value decimal(5,2))
insert into @matches select 1, 1.0
insert into @matches select 1, -1.0
insert into @matches select 2, 2.0
insert into @matches select 2, -2.0
insert into @matches select 2, -2.0
insert into @matches select 3, 3.0
insert into @matches select 3, 3.5
insert into @matches select 3, -3.0
insert into @matches select 3, -3.5
insert into @matches select 4, 4.0
insert into @matches select 4, 4.0
insert into @matches select 4, -4.0
-- Get groups where we have matching positive/negatives, with the same number of each
select mat.groupid, min(case when pos.PositiveCount = neg.NegativeCount then 1 else 0 end) as 'Match'
from @matches mat
LEFT JOIN (select groupid, SUM(1) as 'PositiveCount', Value
from @matches where value > 0 group by groupid, value) pos
on pos.groupid = mat.groupid and pos.value = ABS(mat.value)
LEFT JOIN (select groupid, SUM(1) as 'NegativeCount', Value
from @matches where value < 0 group by groupid, value) neg
on neg.groupid = mat.groupid and neg.value = case when mat.value < 0 then mat.value else mat.value * -1 end
group by mat.groupid
-- If at least one pair within a group don't match, reject
having min(case when pos.PositiveCount = neg.NegativeCount then 1 else 0 end) = 1
答案 4 :(得分:0)
以下内容应返回“失衡”群组:
;with pos as (
select intGroupID, ABS(decAmount) m
from TableName
where decAmount > 0
), neg as (
select intGroupID, ABS(decAmount) m
from TableName
where decAmount < 0
)
select distinct IsNull(p.intGroupID, n.intGroupID) as intGroupID
from pos p
full join neg n on n.id = p.id and abs(n.m - p.m) < 1e-8
where p.m is NULL or n.m is NULL
要获取不成对的元素,select
声明可以更改为以下内容:
select IsNull(p.intGroupID, n.intGroupID) as intGroupID, IsNull(p.m, -n.m) as decAmount
from pos p
full join neg n on n.id = p.id and abs(n.m - p.m) < 1e-8
where p.m is NULL or n.m is NULL
答案 5 :(得分:0)
您可以通过以下方式比较您的值:
declare @t table(id int, amount decimal(4,1))
insert @t 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),(2,-1.0),(2,1.0)
;with a as
(
select count(*) cnt, id, amount
from @t
group by id, amount
)
select id from @t
except
select b.id from a
full join a b
on a.cnt = b.cnt and a.amount = -b.amount
where a.id is null
由于某种原因,我不能写评论,但Daniels评论不正确,我的解决方案确实接受(6,1),(6,-1),(6,0)这是正确的。在问题中没有指定0,因为它是0值,它可以通过eather方式处理。我的回答不接受(3,1.0),(3,1.0),(3,-1.0)
To Blam:不,我不会错过
or b.id is null
我的解决方案与您的解决方案类似,但不完全相同