【发布时间】:2017-02-08 16:49:08
【问题描述】:
我有一个包含客户信息的表格。每个客户都被分配了一个客户 ID(他们的 SSN),他们在开设更多账户时会保留该 ID。两个客户可能在同一个帐户上,每个客户都有自己的 ID。帐号不按日期排序。
我想查找每个客户或客户组的最新帐户。如果两个客户曾经一起使用过一个帐户,我想返回任一客户最近使用过的帐户。
这是一个包含一些可能情况的示例表。
示例表 ACCT:
acctnumber date Cust1ID Cust2ID
10000 '2016-02-01' 1110 NULL --Case0-customer has only ever had
--one account
10001 '2016-02-01' 1111 NULL --Case1-one customer has multiple
10050 '2017-02-01' 1111 NULL --accounts
400050 '2017-06-01' 1111 NULL
10089 '2017-12-08' 1111 NULL
10008 '2016-02-01' 1120 NULL --Case2-customer has account(s) and later
10038 '2016-04-01' 1120 NULL
10058 '2017-02-03' 1120 1121 --gets account(s) with another customer
10002 '2016-02-01' 1112 NULL --Case3-customer has account(s) and later
10052 '2017-02-02' 1113 1112 --becomes the second customer on another
10152 '2017-05-02' 1113 1112 --account(s)
10003 '2016-02-02' 1114 1115 --Case4-customer and second customer
7060 '2017-02-04' 1115 1114 --switch which is first and second
10004 '2016-02-02' 1116 1117 --Case5-second customer later gets
10067 '2017-02-05' 1117 NULL --separate account(s)
10167 '2018-02-05' 1117 NULL
50013 '2016-01-01' 2008 NULL --Case5b -customer has account(s) & later
50014 '2017-02-02' 2008 2009 --gets account(s) with second customer &
50015 '2017-04-04' 2008 NULL --later still first customer gets
100015 '2018-05-05' 2008 NULL --separate account(s)
30005 '2015-02-01' 1118 NULL --Case6-customer has account(s)
10005 '2016-02-01' 1118 NULL
10054 '2017-02-02' 1118 1119 --gets account(s) with another
40055 '2017-03-03' 1118 1119
10101 '2017-04-04' 1119 NULL --who later gets separate account(s)
10201 '2017-05-05' 1119 NULL
30301 '2017-06-06' 1119 NULL
10322 '2018-01-01' 1119 NULL
10007 '2016-02-01' 1122 1123 --Case7-customers play musical chairs
10057 '2017-02-03' 1123 1124
10107 '2017-06-02' 1124 1125
50001 '2016-01-01' 2001 NULL --Case8a-customers with account(s)
50002 '2017-02-02' 2001 2002 --together each later get separate
50003 '2017-03-03' 2001 NULL --account(s)
50004 '2017-04-04' 2002 NULL
50005 '2016-01-01' 2003 NULL --Case8b-customers with account(s)
50006 '2017-02-02' 2003 2004 --together each later get separate
50007 '2017-03-03' 2004 NULL --account(s)
50008 '2017-04-04' 2003 NULL
50017 '2018-03-03' 2004 NULL
50018 '2018-04-04' 2003 NULL
50009 '2016-01-01' 2005 NULL --Case9a-customer has account(s) & later
50010 '2017-02-02' 2005 2006 --gets account(s) with a second customer
50011 '2017-03-03' 2005 2007 --& later still gets account(s) with a
--third customer
50109 '2016-01-01' 2015 NULL --Case9b starts the same as Case9a, but
50110 '2017-02-02' 2015 2016
50111 '2017-03-03' 2015 2017
50112 '2017-04-04' 2015 NULL --after all accounts with other customers
50122 '2017-05-05' 2015 NULL --are complete, the original primary
--customer begins opening individual
--accounts again
期望的结果:
acctnumber date Cust1ID Cust2ID
10000 '2016-02-01' 1110 NULL --Case0
10089 '2017-12-08' 1111 NULL --Case1
10058 '2017-02-03' 1120 1121 --Case2
10152 '2017-05-02' 1113 1112 --Case3
7060 '2017-02-04' 1115 1114 --Case4
10167 '2018-02-05' 1117 NULL --Case5
100015 '2018-05-05' 2008 NULL --Case5b
10322 '2018-01-01' 1119 NULL --Case6
10107 '2017-06-02' 1124 1125 --Case7
50003 '2017-03-03' 2001 NULL --Case8a result 1
50004 '2017-04-04' 2002 NULL --Case8a result 2
50017 '2018-03-03' 2004 NULL --Case8b result 1
50018 '2018-04-04' 2003 NULL --Case8b result 2
50011 '2017-03-03' 2005 2007 --Case9a
50122 '2017-05-05' 2015 NULL --Case9b
或者,我会接受案例 7 输出两个不同的客户组:
10007 '2016-02-01' 1122 1123 --Case7 result 1
10107 '2017-06-02' 1124 1125 --Case7 result 2
因为案例 8a 和 8b 代表公司承认客户值得持有单独的帐户,所以我们希望将他们的组视为拆分,因此它具有单独的结果集。
另外,在大多数场景下,客户有很多账户,混合搭配上述情况加班是很常见的。例如,一个客户可以有五个账户(案例 1),然后再与另一个客户开一个或多个账户(案例 3),有时会更换主要账户持有人(案例 4),然后第一个客户再次开始开设个人账户(案例 5b)。
只要帐户编号是唯一的并且任何客户 ID 匹配,我都会尝试将表加入到自身的副本中。但是,这会删除只有一个帐户的客户,因此我添加了一个与 custid 或帐号不匹配的 cust 联合,以及按 custid 划分的组。
不幸的是,第二部分不仅包括案例 0 中的 custid,而且还有一些不应该被排除在外的 custid。
select
max(date1) as date,
cust1id1 as cust1id
from
(
select
acctnumber as [acctnumber1],
date as [date1],
cust1id as [cust1id1],
cust2id as [cust2id1]
from
acct
) t1
join
(
select
acctnumber as [acctnumber2],
date as [date2],
cust1id as [cust1id2],
cust2id as [cust2id2]
from
acct
) t2
on t1.date1 > t2.date2 and
(t1.cust1id1 = t2.cust1id2 or
t1.cust1id1 = t2.cust2id2 or
t1.cust2id1 = t2.cust2id2)
Group by
cust1id1
union
select
max(date1) as date,
cust1id1 as cust1id
from
(
select
acctnumber as [acctnumber1],
date as [date1],
cust1id as [cust1id1],
cust2id as [cust2id1]
from
acct
) t1
join
(
select
acctnumber as [acctnumber2],
date as [date2],
cust1id as [cust1id2],
cust2id as [cust2id2]
from
acct
) t2
on (t1.acctnumber1 != t2.acctnumber2 and
t1.cust1id1 != t2.cust1id2 and
t1.cust1id1 != t2.cust2id2 and
t1.cust2id1 != t2.cust2id2)
group by
cust1id1
更新
感谢您迄今为止提供的所有出色答案和 cmets。我一直在尝试查询并比较结果。
@VladimirBaranov 提出了一个我以前在 cmets 中没有考虑过其他答案的罕见案例。
与案例 7 类似,如果案例 8 被处理,将是一个奖励,但不是预期的。
案例 9 很重要,应处理 9a 和 9b 的结果。
更新 2
我注意到我原来的 7 个案例存在问题。
在最近的帐户中,当客户不再在帐户中时,总是留下第二个借款人。这完全是无意的,您可以查看这些示例中的任何一个,其中任一客户都可能是最近帐户中的剩余客户。
此外,每个案例都有最少数量的帐户来准确显示案例正在测试的内容,但这并不常见。通常在每个案例的每个步骤中,在客户切换到添加第二个客户之前,可以有 5、10、15 个或更多帐户,然后这两个帐户可以一起拥有许多帐户。
查看我看到的许多答案都有索引、创建、更新和其他特定于能够编辑数据库的子句。不幸的是,我在这个数据库的消费者端,所以我有只读访问权限,我可以用来与数据库交互的程序会自动拒绝它们。
【问题讨论】:
-
这似乎是一个非常糟糕的数据库设计。
-
不幸的是,我在这个数据库的消费者端,他们至少有一个想法是正确的:它被设置为只读。
-
方括号表示 Microsoft SQL Server 语法。 MySQL 不在标识符周围使用方括号。我将更改此问题的标签以表明这一点。
-
为什么 CustID 1116 没有结果集?还是1118?
-
不确定这个数据库设计,你不支持第三个客户吗?但是,这里适用 SQL 最佳实践,即您需要将数据重新格式化为清晰易读的内容,即使您能够编写超级查询来完成这项工作......不要。视图、CTE 和临时表按此顺序出现。
标签: sql sql-server tsql greatest-n-per-group