*SQL:多字段混合去重后编号
SQL SERVER 库表存储人员记录,来自多种源数据,如果两条记录的 Name、Phone、Email 字段之一有重复,则说明这两条记录是同一个人。null 是数据未知,两条记录的字段都为 null 时表示两者默认不重复,是否重复要靠其他字段判断。注意,如果 A 和 B 重复,B 和 C 重复,则 A 和 C 也是重复的。
RegisterId |
Name |
Phone |
|
XXX-00001 |
John Strauss |
241567 |
Null |
XXX-00023 |
Rick Astley |
241567 |
richardastley@gmail.com |
XXX-00003 |
John Strauss |
NULL |
NULL |
XXX-00099 |
NULL |
241567 |
georgeharrison@gmail.com |
XXX-00085 |
NULL |
256819 |
richardastley@gmail.com |
XXX-00016 |
NULL |
NULL |
georgeharrison@gmail.com |
XXX-00007 |
John Deep |
280933 |
NULL |
XXX-00008 |
John Deep |
93484 |
NULL |
XXX-00009 |
Javier Estrada |
94578 |
javier@gmail.com |
XXX-00010 |
NULL |
39939 |
39939@gmail.com |
要求:新增计算列人员编号 no,找到重复的记录,给每组重复的记录赋予一个独立的 no。
RegisterId |
Name |
Phone |
no |
|
XXX-00001 |
John Strauss |
241567 |
1 |
|
XXX-00023 |
Rick Astley |
241567 |
richardastley@gmail.com |
1 |
XXX-00003 |
John Strauss |
1 |
||
XXX-00099 |
241567 |
georgeharrison@gmail.com |
1 |
|
XXX-00085 |
256819 |
richardastley@gmail.com |
1 |
|
XXX-00016 |
georgeharrison@gmail.com |
1 |
||
XXX-00007 |
John Deep |
280933 |
7 |
|
XXX-00008 |
John Deep |
93484 |
7 |
|
XXX-00009 |
Javier Estrada |
94578 |
javier@gmail.com |
9 |
XXX-00010 |
39939 |
39939@gmail.com |
10 |
编写SPL代码
1 |
=mssql.query("select * from tb") |
2 |
=T=A1.derive(#:no) |
3 |
for T.count(T[1:].count( if(no!=T.no && ( (Name && T.Name && Name==T.Name) || (Phone && T.Phone && Phone==T.Phone) || (Email && T.Email && Email==T.Email)), T.no=no=min(no,T.no) ))>0)>0 |
4 |
return T |
A1: 通过JDBC查询数据库。
A2:新增编号列no,缺省为记录序号#。
A3:用死循环遍历记录调整no列,如果某次遍历后有no被调整的情况,则重新遍历,直到所有no都不再调整为止。遍历记录时从上往下进行,当前是第i条记录时,把它依次与第i+1直至最后一条记录比较,如果被认为是重复记录则同步两者的no,取两者间较小的那个。字段值为null时,默认与其他记录不重复。注意null与任何值进行逻辑与运算时,都为false。
count函数返回符合条件的成员的个数,当第i条记录与i+1直至最后一条记录比较的过程中,如果有发生no被调整的动作,则内层的count将大于0,这会导致外层的count也大于0,满足继续循环的条件。
还需要有no!=T.no的条件,确保调整动作中至少有一个no值会变得更小,否则可能出现无法结束的死循环。
英文版 https://c.scudata.com/article/1731663151054