5

intGroupID、decAmount の 2 つの列を持つテーブルがあります。

基本的に、すべての正(+)のdecAmountに対して、等しい反対の負(-)のdecAmountがある場合、結果としてintGroupIDを返すことができるクエリが必要です。

したがって、(id=1,amount=1.0),(1,2.0),(1,-1.0),(1,-2.0) のテーブルは、1 の intGroupID を返します。これは、正の数ごとに負の数が存在するためです。一致する数。

これまでのところ、同じ数の 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

おそらくペアを見つけてテーブルから削除し、正/負の一致がなくなったらテーブルに何か残っているかどうかを確認することで、このテーブルを確認するより良い方法があると思いますが、そうする必要はありません。再帰/カーソルを使用します。

4

6 に答える 6

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
于 2013-07-25T15:28:34.040 に答える
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
于 2013-07-25T14:56:30.533 に答える
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
于 2013-07-25T14:48:51.087 に答える
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

何らかの理由でコメントを書くことはできませんが、ダニエルズのコメントは正しくありません。私のソリューションは (6,1),(6,-1),(6,0) を受け入れますが、これは正しい可能性があります。0 は質問で指定されておらず、0 の値であるため、別の方法で処理できます。私の答えは (3,1.0),(3,1.0),(3,-1.0) を受け入れません

非難する: いいえ、私は行方不明ではありません

or b.id is null

私の解決策はあなたのものと似ていますが、まったく同じではありません

于 2013-07-25T14:51:24.260 に答える
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
于 2013-07-25T14:44:08.880 に答える