基于多行的SQL查询

时间:2015-07-31 00:11:51

标签: sql sql-server rows

我需要弄清楚如何在SQL中使用它:

如果C = 1,则在C = 1的行中找到B是B的负数的下一行,并且两行的A值相同。如果这两行之间的D差异大于1天,则返回该行,其中C = 1

样本数据

A       B        C        D
1       10.00    0        2015-01-01
1       15.00    1        2015-01-02
1      -15.00    0        2015-01-03
2        5.00    1        2015-01-03
2       -5.00    0        2015-01-05
3        1.00    1        2015-01-03
3        2.00    0        2015-01-04
3       -1.00    0        2015-01-05

预期产出:

2        5.00    1        2015-01-03
3        1.00    1        2015-01-03

3 个答案:

答案 0 :(得分:0)

如果“next”表示d栏中的后一个值,则可以将条件转换为exists子句:

select t.*
from table t
where t.c = 1 and
      exists (select 1
              from table t2
              where t2.d >= datedadd(day, 1, t.d) and t2.a = t.a and
                    t2.b = - t.b
             );

注意:如果b是浮点数,您可能需要容差,例如abs(t2.b + t.b) < 0.001

答案 1 :(得分:0)

select m1.*
from myTable m1
inner join myTable m2
on m1.a = m2.a                     -- same a
and m1.b = m2.b * -1               -- b is the negative of b
and m1.d < m2.d                    -- the next row
and dateadd(day, 1, m1.d ) > m2.d  -- difference is greater than 1 day
where m1.c = 1

union all 

select m2.*
from myTable m1
inner join myTable m2
on m1.a = m2.a
and m1.b = m2.b * -1
and m1.d < m2.d
and dateadd(day, 1, m1.d ) <= m2.d
where m1.c = 1

答案 2 :(得分:0)

正如一位评论者提到的那样,你必须要有某种“排序”....我已经介绍了一个tablekey,你可以将Over / OrderBY更改为已经存在的东西...但是你必须有某种订购机制除了“这里是他们”。

我不是说我的查询是最短的查询...但是,当我有“时髦的商业规则”时,我会选择一点点冗长而不是简洁,所以如果我必须回去维护它,我可以以某种方式分解“部分”是有道理的。

这是一个让你大部分都在那里的答案。 基本上,我根据你的标准去钓鱼“MagicNewRow”。 但它只能起作用,因为我能够通过一些排序机制创建一个ComputedRowId。 (正如我之前解释的那样)

declare @holder table (TableKey int identity(1,1) , 
Col1 int, Col2 decimal, Col3 bit , Col4 smalldatetime , ComputedRowID int )
insert into @holder (Col1, Col2, Col3, Col4)
select 1  ,     10.00 ,   0,        '2015-01-01'
union all select 1  ,     15.00,1,        '2015-01-02'
union all select 1  ,    -15.00,    0,        '2015-01-03'
union all select 2  ,      5.00,    1,        '2015-01-03'
union all select 2  ,     -5.00,    0,        '2015-01-05'
union all select 3  ,      1.00,    1,        '2015-01-03'
union all select 3  ,      2.00,    0,        '2015-01-04'
union all select 3  ,     -1.00,    0,        '2015-01-05'

--select * from @holder

Update @holder Set ComputedRowID
= derived1.ROWID
from
@holder hold join

--Select * from
(
select TableKey, Col1, Col2, Col3, Col4 , ROW_NUMBER() over (order by TableKey) as ROWID
from @holder) as derived1
on hold.TableKey = derived1.TableKey
/* 
f C=1 then find the next row where B is the negative of B in the row
 where C=1 and the value of A is the same for both rows. 
 If the difference in D between those 2 rows is greater than 1 day, 
then return that row where C=1*/

;WITH
  cteCIsOne /*Col1, Col2, Col3, Col4, ROWID )*/
  AS
  (
    Select holderAlias.Col1, holderAlias.Col2, holderAlias.Col3, holderAlias.Col4, holderAlias.ComputedRowID
    from @holder holderAlias
    where Col3 = 1
  )
  ,
    cteRowsGreaterThanCurrentRowIdAndNegRuleApplies /*(Col1, Col2, Col3, Col4, ROWID )*/
  AS
  (
    Select holderAlias.Col1, holderAlias.Col2, holderAlias.Col3, holderAlias.Col4,
     holderAlias.ComputedRowID, 
     MagicNextRowComputedRowID = (select top 1 ComputedRowID from cteCIsOne cte1 
        where holderAlias.ComputedRowID > cte1.ComputedRowID and holderAlias.col2 = (-1 * cte1.col2) )
    from @holder holderAlias
  )

Select Col1, Col2, Col3, Col4 , ComputedRowID , MagicNextRowComputedRowID, MagicNextRowDate
, MyDateDiff = datediff(d, MagicNextRowDate, Col4)
from
(
SELECT Col1, Col2, Col3, Col4 , ComputedRowID , MagicNextRowComputedRowID
,
MagicNextRowDate = (select top 1 Col4 from @holder hold where hold.ComputedRowID = cteAlias2.MagicNextRowComputedRowID)
from cteRowsGreaterThanCurrentRowIdAndNegRuleApplies cteAlias2
) as derived
where derived.MagicNextRowComputedRowID IS NOT NULL 
and
datediff(d, MagicNextRowDate, Col4) > 1