MS SQL:如何在多个用户的另一个日期(付款日期)之前获取最新日期(billdate)?
示例表如下:MS SQL:如何在多个用户的另一个日期(付款日期)之前获取最新日期(billdate)?
表1
userid | billdate
user1 | 2017-06-01
user1 | 2017-05-01
user1 | 2017-04-01
user2 | 2017-06-01
user2 | 2017-05-01
表2
userid | paymentdate
user1 | 2017-06-01
user1 | 2017-06-02
user1 | 2017-05-02
user2 | 2017-06-30
user2 | 2017-05-30
希望的输出提前
userid | billdate | paymentdate
user1 | 2017-05-01 | 2017-06-01
user1 | 2017-06-01 | 2017-06-02
user1 | 2017-05-01 | 2017-05-02
user2 | 2017-06-01 | 2017-06-30
user2 | 2017-05-01 | 2017-05-30
由于
增加了一个场景:如果同一月份有多个付款,该怎么办?并且对于每个付款日期,先前的帐单日期应该在期望的输出中
如果你只想返回那里是一个Bill
和Payment
记录的记录,那么我们首先需要作出一些假设 - 即不会有任何两个Bill
付款之间有两个Payment
记录,或在同一天支付两笔Bill
付款。
假设这一切,你可以使用cross apply
获得最新Payment
记录每个Bill
记录,不返回任何东西在没有Payment
记录可供选择:
declare @Bills table(userid nvarchar(10),billdate date);
insert into @Bills values ('user1','2017-06-01'),('user1','2017-05-01'),('user1','2017-04-01'),('user2','2017-06-01'),('user2','2017-05-01');
declare @Payments table(userid nvarchar(10),paymentdate date);
insert into @Payments values ('user1','2017-06-01'),('user1','2017-06-02'),('user1','2017-05-02'),('user2','2017-06-30'),('user2','2017-05-30');
select p.userid
,ba.billdate
,p.paymentdate
from @Payments p
cross apply(select top 1 billdate
from @Bills b
where p.userid = b.userid
and b.billdate < p.paymentdate
order by b.billdate desc
) ba
order by p.userid
,ba.billdate desc
,p.paymentdate desc;
输出:
+--------+------------+-------------+
| userid | billdate | paymentdate |
+--------+------------+-------------+
| user1 | 2017-06-01 | 2017-06-02 |
| user1 | 2017-05-01 | 2017-06-01 |
| user1 | 2017-05-01 | 2017-05-02 |
| user2 | 2017-06-01 | 2017-06-30 |
| user2 | 2017-05-01 | 2017-05-30 |
+--------+------------+-------------+
感谢您的详细回复。如果在我的现实生活场景中存在多笔付款,那么该怎么办。 :) –
@HopetoChristianChophi正在更新我的答案,就像你正在写评论:) – iamdave
似乎工作..只是确认与我的活的数据库...一些活的情况可能已经在示例场景中被忽略...将更新如果我能找到它,或者在确认后将其标记为答案。请给我一些时间。再次感谢 –
您似乎想要加入表格,但没有密钥。 row_number()
可以提供关键:
select t1.*, t2.paymentdate
from (select t1.*,
row_number() over (partition by userid order by billdate) as seqnum
from t1
) t1 join
(select t2.*,
row_number() over (partition by userid order by paymentdate) as seqnum
from t2
) t2
on t1.userid = t2.userid and t1.seqnum = t2.seqnum;
你需要从Table01所有行,然后得到的只有一行从TABLE02升序排列。 Table02行通过用户标识和日期连接(billdate < = paymentdate)。顶部(1)的外部应用将会诀窍。
drop table if exists dbo.Table01;
drop table if exists dbo.Table02;
create table dbo.Table01 (
userid varchar(100)
, billdate date
);
create table dbo.Table02 (
userid varchar(100)
, paymentdate date
);
insert into dbo.Table01 (userid, billdate)
values ('user1', '2017-06-01'), ('user1', '2017-05-01')
, ('user2', '2017-06-01'), ('user2', '2017-05-01');
insert into dbo.Table02 (userid, paymentdate)
values ('user1', '2017-06-02'), ('user1', '2017-05-02')
, ('user2', '2017-06-30'), ('user2', '2017-05-30');
select
*
from dbo.Table01 t1
outer apply (
select
top (1)
t2.paymentdate
from dbo.Table02 t2
where t1.userid = t2.userid
and t1.billdate <= t2.paymentdate
order by t2.paymentdate asc
) tt
有两种可能的解决方案:
首先
合并表为一体。这将使哪些日期属于哪个账单和哪个用户更清楚。因此,所需的输出是您正在使用的表格。如果用户已被记帐但尚未付款。付款日期是NULL
。
二
添加主键到table 1
和表2中使用它作为外键,像这样:
bill_id | userid |s billdate 1 | user1 |s 2017-06-01 2 | user1 |s 2017-05-01 3 | user2 |s 2017-06-01 4 | user2 |s 2017-05-01
表2
bill_id | userid |s paymentdate 1 | user1 |s 2017-06-02 2 | user1 |s 2017-05-02 3 | user2 |s 2017-06-30 4 | user2 |s 2017-05-30
现在你可以轻松获得连接:
SELECT table1.*, table2.paymentdate FROM table1 LEFT JOIN table2 ON table1.bill_id = table2.bill_id;
如果'user1'在'表2'中有三条记录怎么办? –
我认为您应该将您的付款与帐单关联起来。如果我没有收到账单,我永远不会付钱给你,因此链接应该始终存在。所以基本上你必须在付款表中添加一列“bill_ID”。如果一笔交易支付多笔账单,这一笔将会有麻烦。您可能需要在前端应用程序 – Luke
上处理该问题。但假设user1只有这些记录。 –