首先,一些虚构数据:
方案:
我有一张桌子,上面记录着我所有的交易,例如库存变动和其他交易。我需要生成一个报告,该报告将显示进入特定create table #testm
(
transdate date,
item nvarchar(20),
qty int,
whse nvarchar(10),
loc nvarchar(10)
)
insert into #testm (transdate, item, qty, whse, loc)
values ('20180601', '123', 100, 'main', 'qc'),
('20180602', '123', -100, 'main', 'qc'),
('20180603', '123', 100, 'main', 'qc'),
('20180604', '123', -100, 'main', 'qc'),
('20180602', '1234', 100, 'main', 'qc'),
('20180602', '1234', -100, 'main', 'notqc')
并退出该项目的数据(#testm
表字段)。但是,我只需要对每个“出口”计数一次,因此它不会将自己与匹配项目和数量的其他“入口”联接起来。然后,我需要查看该项目在该loc
中花费了多少时间。特殊情况是项目尚未离开loc
时,它应该在loc
中的datediff()
中在查询的第二部分显示空值。
在上面的getdate()
语句中,预期结果是将第1行与2、3、4、5完全匹配(因为还没有退出,而第6行的insert
错误),并且跳过第6行,因为loc
不是我要找的那个。
结果应该像这样
loc
这是我的尝试:
transdate item qty whse loc td2 it2 qt2 wh2 lo2 datediffhour
2018-06-01 123 100 main qc 2018-06-02 123 -100 main qc 24
2018-06-02 1234 100 main qc NULL NULL NULL NULL NULL 1056
2018-06-03 123 100 main qc 2018-06-04 123 -100 main qc 24
2个问题:
它跳过了第5行
select * from
(
select tin.transdate, tin.item, tin.qty, tin.whse, tin.loc, DENSE_RANK() over(partition by tin.transdate order by tout.transdate) as firstrank,
DENSE_RANK() over (partition by tout.transdate order by tin.item) as secondrank, tout.transdate as td2, tout.item as it2, tout.qty as qt2, tout.whse as wh2, tout.loc as lo2,
datediff(hour, tin.transdate, isnull(tout.transdate, getdate())) as datediffhour
from #testm as tin
left join #testm as tout on tin.item = tout.item and tin.whse = tout.whse and tin.transdate <= tout.transdate and tin.qty = -1*tout.qty
where tin.loc = 'qc' and tout.loc = 'qc'
) as t
where (firstrank = secondrank or t.td2 is null) and t.qty > 0
order by t.transdate
和secondrank
只是猜测,因为我并不真正熟悉firstrank
-我什至使用得还对吗?
答案 0 :(得分:1)
我使用dense_rank()
代替了t_in.transdate < t_out.transdate
。这里只需要一个。请注意,我们有一个<=
条件,而不是t_out.loc = 'qc'
。
显示第5行没有退出匹配项的关键是将条件WHERE
设置为左联接条件而不是 INNER JOIN
子句,因为在这里它的作用就像您正在应用{{1 }} 。
select
transdate, item, qty, whse, loc,
td2, it2, qt2, wh2, lo2, datediffhour
from (
select
t_in.transdate, t_in.item, t_in.qty, t_in.whse, t_in.loc,
t_out.transdate as td2, t_out.item as it2, t_out.qty as qt2, t_out.whse as wh2, t_out.loc as lo2,
datediff(hour, t_in.transdate, isnull(t_out.transdate, getdate())) as datediffhour,
row_number() over (partition by t_in.item, t_in.transdate order by t_in.transdate) as rn
from #testm t_in
left join #testm t_out on
t_in.item = t_out.item
and t_in.whse = t_out.whse
and t_in.qty = -1 * t_out.qty
and t_in.transdate < t_out.transdate
and t_out.loc = 'qc'
where
t_in.qty > 0
and t_in.loc = 'qc'
) t
where rn = 1 -- pick up only first matching "exit"
order by transdate
答案 1 :(得分:0)
使用Row_Number()
。当您连续在同一地点购买相同物品并随后出售(输入/退出)时,此功能将无效。
Select * from
(Select test1.*,
datediff(hour, test1.transdate, Coalesce(test2.transdate, getdate())) as datediffhour,
row_number() over (partition by test1.item, test1.loc, test1.transdate order by test1.transdate) as ranking
from #testm test1
left join #testm test2
on test1.item = test2.item
and test1.loc = test2.loc
and test1.whse = test2.whse
and test1.qty + test2.qty = 0
and test1.transdate < test2.transdate
where test1.qty > 0)c
where ranking=1
答案 2 :(得分:0)
使用outer apply
。像这样:
select t.*, tnext.*
from #testm t outer apply
(select top (1) tnext.*
from #testm tnext
where tnext.loc = t.loc and tnext.item = t.item and
tnext.transdate > t.transdate
order by tnext.transdate asc
) tnext;