TSQL仅选择值不被另一行取消的行

时间:2017-01-24 05:26:15

标签: sql-server

我有一张带复合键的表。每行都有一个值。不应返回具有负值的行。如果存在两行,其中Key1和Key2相同且一行中的值与另一行* -1中的值相同,则不应返回任何行。但是,如果存在具有相同Key1的第三行和具有正值的Key2,则应返回该行。这是一个示例表:

Key1    Key2   Key3    Value
----------------------------
1       1      1       500.00
1       1      2      -500.00
1       1      3       500.00
1       2      1       250.00
1       3      1       100.00
1       3      2      -100.00

查询结果应为:

Key1    Key2    Key3   Value
----------------------------
1       1       3      500.00
1       2       1      250.00

那么什么是可以给我这个结果的查询?谢谢!

其他信息:

@Jacky,不应返回100.00,因为Key1和Key2相同时存在另一行,但该值与-100.00完全相反。

@ Eralper,1,1,1和1,1,2相互抵消,但应返回1,1,3。

@ Zohar,我正在使用SQL Server 2014 SP1。 Key1和Key2相同的行是唯一计为匹配的行。

另外,抱歉我最初没有包含此内容,当应该返回一行时,它应该是Key3列中值最大的行。例如,1,1,2取消1,1,1,并且应返回1,1,3。

这些是我们的采购部门已输入并且我们的用户可以支付的行的表格。对于1,1,1,采购部表示此行可以现在支付。后来,在1,1,2,采购说这不能支付。之后,在1,1,3采购上说,可以毕竟可以支付。

这就是为什么在这个时间点,我只能返回结果表中显示的2行。

2 个答案:

答案 0 :(得分:1)

这就是我最终的结果:

SELECT
    Key1
    ,Key2
    ,Key3
    ,Value
FROM (
        SELECT
              Key1,
              Key2,
              Key3,
              Value,
              SUM(Value) OVER (PARTITION BY Key1, Key2, ABS(Value)) as valueSum,
              ROW_NUMBER() OVER (PARTITION BY Key1, Key2, ABS(Value) ORDER BY Key3 DESC) as rowNumber
          FROM [Etads].[dbo].[TestTlsc] 
      ) a
WHERE valueSum > 0
    AND rowNumber = 1

如果值"取消",则所有值的总和将为零。因此" WHERE valueSum> 0"

ORDERing BY Key3 DESC将max Key3置于rowNumber = 1。

谢谢!

答案 1 :(得分:0)

请在测试环境中测试SQL CTE query

正如我上面评论的那样,我认为1,1,1是输出列表的候选者,因为下面的查询建议

我还使用Row_Number()SQL函数到Count() with Over clause

我知道这是一个复杂的查询,我讨厌它:) 但是你的要求一目了然有点难以回答

我希望它有所帮助,

with cteKeys as (
select ROW_NUMBER() over (Order By key1,key2,key3) Id, * from keys
), cteList as (
    select
        k1.Id as key1Id,
        k2.Id as key2Id,         
        k1.key1 as key11,
        k1.key2 as key12,
        k1.key3 as key13,
        k2.key1 as key21,
        k2.key2 as key22,
        k2.key3 as key23,
        k1.value as key1val,
        k2.value as key2val,
        case when   (
                k1.key1 = k2.key1 and 
                k1.key2 = k2.key2 and
                k1.key3 <> k2.key3 
                ) then 110
                when (
                k1.key1 = k2.key1 and 
                k1.key2 <> k2.key2 and
                k1.key3 = k2.key3 
                ) then 101
                when (
                k1.key1 <> k2.key1 and 
                k1.key2 = k2.key2 and 
                k1.key3 = k2.key3 
                ) then 011
        end as match
    from cteKeys k1
    left join cteKeys k2 on 
    (
    k1.key1 = k2.key1 and 
    k1.key2 = k2.key2 and
    k1.key3 <> k2.key3 
    ) or
    (
    k1.key1 = k2.key1 and 
    k1.key2 <> k2.key2 and
    k1.key3 = k2.key3 
    ) or
    (
    k1.key1 <> k2.key1 and 
    k1.key2 = k2.key2 and 
    k1.key3 = k2.key3 
    )
)
--select * from cteList

, cteMatches as (
    select 
        *, 
        count(key2Id) over (partition by key1Id, match) cnt,
        isDeleted0 = case when (count(key2Id) over (partition by key1Id, match)) = 0 then 0 else null end
    from cteList
), resultCTE as (
select *, 
    case when (cnt = 2 and key1val <> -1 * key2val and key1val > 0 and key2val > 0) then 0 end as isDeleted2,
    case when (cnt = 1 and key1val = -1 * key2val) then 1 end as isDeleted1
from cteMatches
)
--select * from resultCTE
, final as (
select * --distinct key1Id, key11,key12,key13 
from resultCTE
where isDeleted0 = 0 

union all

select * --distinct key1Id, key11,key12,key13 
from resultCTE
where isDeleted2 = 0
and not exists (
    select * from resultCTE t where t.key1Id = resultCTE.key1Id and isDeleted1 = 1
)

union all

select * from resultCTE where coalesce(coalesce(isDeleted0,isDeleted2),isDeleted1) is null
)
--select * from cteMatches

select distinct * from cteKeys where Id in (

    select key1Id
    from final

) and Value > 0

这是输出

enter image description here