我目前正在扩展我几个月前写的客户列表查询,以包括有关上次定期审核的更多信息。 工作正在Teradata SQL上运行我们的数据仓库。 这是我正在使用的代码的一段,实际查询大约200行。
SELECT DISTINCT
k.customerID
,k.name
,a.CountryCode
,CASE WHEN Account.actorID IS NOT NULL THEN 1 ELSE 0 END AS hasAccount
,id.ControlDate
,id.ControlBy
FROM customer k
LEFT JOIN agreement a ON k.actorID = a.actorID
LEFT JOIN identification id ON k.actorID = id.actorID
INNER JOIN (SELECT DISTINCT actorID, MAX(ControlDate) AS LastControl FROM identification GROUP BY actorID) id2
ON k.actorID = id2.actorID AND id.ControlDate = id2.LastControl
LEFT JOIN (SELECT DISTINCT actorID FROM agreement a WHERE a.activeAgreement = 'Y' and a.Product IN ('6774', '6775') Account ON k.actorid = Account.actorID
WHERE
k.customerstatus = 'Active'
;
麻烦在于INNER JOIN
语句。
运行此命令时,我得到1769行,但是如果我删除了INNER JOIN
和两个id
。 SELECT
中的短语,总和最多会弹出2117。
区别在于NULL
上的id.ControlDate
个值。
但是,如果我使用LEFT JOIN
而不是INNER JOIN
,则会得到大约6800行,因为许多客户已经多次更新/执行了控制。
我该如何解决?
编辑:为澄清起见,我希望每actorID
行一次,以获得最新的controlDate
或NULL
值
Edit2 :按照@Thorsten Kettner的要求进行解释。
每个客户ActorID
和CustomerID
都是唯一的。但是,此值是由系统生成的,而customerID
通常是社会安全号码,公司注册号等。我们倾向于在我们的CRM系统中使用CustomerID
作为查找值。
一位客户(或演员)可以根据他们与我们的关系签订许多协议,并且可以进行许多定期审查,因为法律要求我们定期进行资产组合审计。
这是一些示例数据:
1)不使用INNER JOIN
语句:
actorID客户名称国家/地区hasAccount ControlDate ControlBy
278´228美国银行NA贸易操作0 ?
275330美国分行与信托公司美国0 04.02.2016 AD09853
275 169 CITIZENS Bank NA NA 1 12.03.2018 AB96358
275169公民银行 NA美国1 2016年11月16日AB02890
275169公民银行 不适用美国1 2015年12月15日AB62775
275169公民银行 不适用美国1 2011年10月11日AB68786
264072摩根大通证券交易所借贷资产 管理US 0 11.10.2017 AB45546
264061国际发展 协会美国0 2018年5月29日AB45546
263 995个锡安公司成立 N.A美国1 2015年3月19日AB43584
263 995个锡安公司成立 N.A US 1 09.11.2016 AB02890
263 995个锡安公司成立 N.A美国1 2018年3月13日AB45546
263 995个锡安公司成立 N.A US 1 06.10.2011 AB68786
263939花旗集团全球市场 Inc美国1 2015年12月22日AB62775
263939花旗集团全球市场 Inc美国1 2012年12月12日AB68786
262 114 Prebon金融产品 Inc美国0 2015年12月30日AB24733
262113摩根大通证券 LLC美国0 18.06.2018 AB45546
261795美联储 系统US 0 05.11.2015 AB62759
261795美联储 系统US 0 05.06.2014 AB31660
2)使用INNER JOIN
语句:
actorID客户名称国家/地区hasAccount ControlDate ControlBy
275330美国分行与信托公司美国0 04.02.2016 AD09853
275 169 CITIZENS Bank NA NA 1 12.03.2018 AB96358
264072摩根大通证券交易所美国贷款资产管理0 2017年10月10日AB45546
264061国际开发协会美国0 2018年5月29日AB45546
263995 Zions Bancorporation N.A US 1 13.03.2018 AB45546
263939 Citigroup Global Markets Inc美国1 2015年12月22日AB62775
262 114 Prebon Financial Products Inc美国0 2015年12月30日AB24733
262 113摩根大通证券有限责任公司美国0 2018年6月18日AB45546
261795美国联邦储备系统0 2015年11月5日AB62759
如您所见,actorID 278 228
消失了,这不好……
答案 0 :(得分:1)
您可以对TOP 1 WITH TIES
排序使用ROW_NUMBER
来获取仅具有每个客户最新日期的记录。
select
c.customerid,
c.name,
a.countrycode,
case when c.actorid in
(select * from agreement where activeagreement = 'Y' and product in ('6774', '6775'))
then 1 else 0 end as hasaccount,
i.controldate,
i.controlby
from customer c
left join agreement a on a.actorid = c.actorid
left join
(
select top 1 with ties *
from identification
order by row_number() over (partition by actorid order by controldate desc)
) i on i.actorid = c.actorid
where c.customerstatus = 'Active';
更新:以上答案不适用于OP,因此我提供了以下两种可行的替代方案:
left join
(
select
actorid, controlby, controldate,
max(controlby) over (partition by actorid) as max_controldate
from identification
) i on i.actorid = c.actorid and i.controldate = i.max_controldate.
和
left join
(
select *
from identification
qualify row_number() over (partition by actorid order by controldate desc) = 1)
) i on i.actorid = c.actorid. – Thorsten
使用QUALIFY
的最后一个选项是执行此操作的Teradata方法。 QUALIFY
是SQL标准的teradata扩展。另两种方法是标准SQL。
答案 1 :(得分:0)
最快的解决方案可能是使用ISNULL。
在您编写MAX(ControlDate)
的位置添加MAX(ISNULL(ControlDate,'1970-01-01'))
(或您拥有的任何默认日期)
这将替换NULL并使查询正常工作。
我希望它会有所帮助。 彼得