SQL分区和分析函数的使用
Posted
技术标签:
【中文标题】SQL分区和分析函数的使用【英文标题】:SQL partitions and use of analytical functions 【发布时间】:2015-03-24 18:07:23 【问题描述】:我一直在尝试创建一个包含 2 列 party_id 和 match_party_id 的表,用于识别重复项,如下所述:
正如您在查看 [First_NM+Last_NM+Zip_CD] 时所看到的,我们可以识别出很少的重复记录。我想匹配这个并将它们保留在最常见的party_id 的保护伞中
PARTY_ID FIRST_NM LAST_NM ZIP_CD
----------------------------------------
95678 JANE DOE 7075
12345 JOHN DOE 7000
10000 JOHN DOE 7075
10000 JOHN DOE 7075
95678 JOHN DOE 7075
95678 JOHN DOE 7075
95678 JOHN DOE 7075
88648 JOHN DOE 7075
88648 JOHN DOE 7075
23456 JOHN DOE 7075
95678 SAM DOE 7075
95678 SAM DOE 7075
需要的输出
Party_ID Matched_ID
-----------------------
95678 10000
95678 88648
95678 23456
因为在重复的分区中,我们已经确定了 4 个不同的 party_id 即 95678,10000,88648 和 23456 和 95678 出现的次数最多,因此需要将所有其他 party_id 与该 party_id 匹配。
这是我正在使用的代码。但 LEAD_PI 空值失败
SELECT MAX_PI AS PARTY_ID, LEAD_PI AS MATCHED_ID from
(SELECT DISTINCT B.FIRST_NM, B.MDDL_NM, B.LAST_NM, B.ZIP_CD,MAX_PI,LEAD_PI,
FROM (SELECT I.PARTY_ID,I.FIRST_NM, I.MDDL_NM, I.LAST_NM,A.ZIP_CD,
LEAD(I.PARTY_ID) OVER (PARTITION BY I.FIRST_NM, I.MDDL_NM, I.LAST_NM, A.ZIP_CD ORDER BY I.FIRST_NM, I.MDDL_NM,I.LAST_NM, A.ZIP_CD) AS LEAD_PI, MAX(I.PARTY_ID) OVER (PARTITION BY I.FIRST_NM, I.MDDL_NM, I.LAST_NM, A.ZIP_CD) AS MAX_PI
FROM INDVDL I JOIN PARTY_ADDR A
ON I.PARTY_ID = A.PARTY_ID
) B
WHERE MIN_PI <> MAX_PI
AND MAX_PI <> nvl(LEAD_PI,0)
【问题讨论】:
这是用于 oracle rdbms 如果两个party_id 匹配,并且出现的次数相同怎么办?您如何选择与其他人匹配的? 在那种情况下,我们可以选择max函数并选择一个大于另一个的party_id。 我们可以放宽party_id(最大或最大等)列的条件,但绝对要求是有一个party_id 作为伞形party_id,它不应该出现在分区的match_id 一侧 我并不完全清楚输入集中的所有记录是否都应该是重复的,因为它们的名称并不相同(这是您声明的查找方法的一部分重复),但它们在某些时候确实都有一个共享的party_id
。另外,为什么12345
不在结果集中? JOHN DOE
拥有 party_id
,以及其他所有的。这是疏忽还是故意的?
【参考方案1】:
如果您的基表不包含任何完全重复的行(而且我不确定这种完全重复的意义是什么),那会更简单一些,但是您可以按照描述的数据来完成。看起来像这样的东西会做你想做的事:
SELECT DISTINCT party_id, matched_id
FROM (
SELECT
MAX(i.party_id) OVER (
PARTITION BY i.first_nm, i.middle_nm, i.last_nm, a.zip_cd
) AS party_id,
i.party_id AS matched_id
FROM
indvdl i
JOIN party_addr a
ON i.party_id = a.party_id
)
WHERE party_id != matched_id
内联视图使该查询的表达式稍微简单一些,但我认为您可以不用。不使用窗口函数也可以得到你想要的结果:
WITH nz AS (SELECT i.party_id, i.first_nm, i.last_nm, a.zip_cd
FROM indvdl i JOIN party_addr a ON i.party_id = a.party_id)
SELECT DISTINCT
ref.party_id AS party_id,
matched.party_id AS matched_id
FROM (
SELECT MAX(party_id) AS party_id, first_nm, last_nm, zip_cd
FROM nz
GROUP BY first_nm, last_nm, zip_cd
HAVING MAX(party_id) != MIN(party_id)
) ref
JOIN nz matched
ON ref.first_nm = matched.first_nm
AND ref.last_nm = matched.last_nm
AND ref.zip_cd = matched.zip_cd
WHERE ref.party_id != matched.party_id
无论哪种方式,我都怀疑LEAD()
函数并没有按照您的想法做,而且我确信它没有做您需要的工作。
【讨论】:
以上是关于SQL分区和分析函数的使用的主要内容,如果未能解决你的问题,请参考以下文章