在 T-SQL 中按自定义函数分组
Group by custom function in T-SQL
我有 table 个人,其中可能有重复。我的目标是 return 列出可能的重复项,以便我们可以将它们组合成一个新人。
显然,我想按 first_name
和 last_name
分组。但是,如果两个人的记录都有一个定义的 birth_date
并且这些日期不同,那么我想排除这些记录,因为很可能这些人不同但碰巧有相同的名字。
另一个需要注意的是,在我们的系统(我继承的)中,birth_date
列是 NOT NULL
,未指定的 birth_date
设置为 '1900-01-01'
.
有什么方法可以 GROUP BY
一个自定义函数(或使用其他一些聪明的逻辑),它要么只比较 birth_date
列,检查两者是否都不是默认日期,或者它们是否相同,或者接受参数,比如每个 person_id
并将记录相互比较,returning a BIT
来决定它们是否应该算作同一组?
我想避免使用 CLR 定义的聚合函数(因为我对它没有经验)。
到目前为止(没有 birth_date
比较)我的查询是:
SELECT *
FROM core_person P
WHERE last_name + ',' + first_name IN
(SELECT last_name + ',' + first_name "name"
FROM core_person
GROUP BY last_name + ',' + first_name
HAVING COUNT(*) > 1)
ORDER BY last_name + ',' + first_name
我想在 GROUP BY
子句中添加一些内容来比较出生日期。
除了分组,这样的方法对你有用吗?
select * from MyTable a
left join MyTable b
on a.person_id < b.person_id
and a.first_name = b.first_name
and a.last_name = b.last_name
and (
a.birthdate = b.birthdate
or a.birthdate = '1900-1-1'
or b.birthdate = '1900-1-1'
)
它匹配姓氏和名字匹配的行,并且生日匹配或一个生日是您的占位符值。联接的 person_ID 部分删除了重复项(例如,1 匹配到 2,然后是另一行,其中 2 匹配到 1,或者 1 匹配到 1)。
您可能希望扩大名称的匹配标准以查看前几个字符或使用 SOUNDEX
,但您的匹配可能需要更多的手动排序作为最后一步。
编辑:为了 return 在 table 中可能重复的所有记录的列表,与其匹配项无关,请改用此列表:
select distinct a.* from MyTable a
inner join MyTable b
on a.person_id <> b.person_id
and a.first_name = b.first_name
and a.last_name = b.last_name
and (
a.birthdate = b.birthdate
or a.birthdate = '1900-1-1'
or b.birthdate = '1900-1-1'
)
order by a.first_name, a.last_name, a.birthdate
如果日期等于 1/1/1900,您可以使用 nullif 函数 return 空值,因为 nullif(Birthday,'1/1/1900')
对您有利。
此查询可以让您开始查看所有记录及其可能的匹配项:
select p1.person_id
from core_person p1
join core_person p2
on p1.person_id <> p2.person_id
and LEFT(p1.first_name,5) = LEFT(p2.first_name,5)
and LEFT(p1.last_name,5) = LEFT(p2.last_name,5)
and isnull(nullif(p1.Birthday,'1/1/1900'), p2.Birthday) = isnull(nullif(p2.Birthday,'1/1/1900'), p1.Birthday)
group by p1.person_id
如果其中一个生日等于 1/1/1900,它会将生日与自身进行比较,否则它只会在两个记录中的生日相等时加入。
如果您不想看到您的匹配项,您可以使用上述查询的变体作为子查询 return 只有重复的 id 值:
select core_person
from core_person
where person_id in
(
select p1.person_id
from core_person p1
join core_person p2
on p1.person_id <> p2.person_id
and LEFT(p1.first_name,5) = LEFT(p2.first_name,5)
and LEFT(p1.last_name,5) = LEFT(p2.last_name,5)
and isnull(nullif(p1.Birthday,'1/1/1900'), p2.Birthday) = isnull(nullif(p2.Birthday,'1/1/1900'), p1.Birthday)
group by p1.person_id
)
我有 table 个人,其中可能有重复。我的目标是 return 列出可能的重复项,以便我们可以将它们组合成一个新人。
显然,我想按 first_name
和 last_name
分组。但是,如果两个人的记录都有一个定义的 birth_date
并且这些日期不同,那么我想排除这些记录,因为很可能这些人不同但碰巧有相同的名字。
另一个需要注意的是,在我们的系统(我继承的)中,birth_date
列是 NOT NULL
,未指定的 birth_date
设置为 '1900-01-01'
.
有什么方法可以 GROUP BY
一个自定义函数(或使用其他一些聪明的逻辑),它要么只比较 birth_date
列,检查两者是否都不是默认日期,或者它们是否相同,或者接受参数,比如每个 person_id
并将记录相互比较,returning a BIT
来决定它们是否应该算作同一组?
我想避免使用 CLR 定义的聚合函数(因为我对它没有经验)。
到目前为止(没有 birth_date
比较)我的查询是:
SELECT *
FROM core_person P
WHERE last_name + ',' + first_name IN
(SELECT last_name + ',' + first_name "name"
FROM core_person
GROUP BY last_name + ',' + first_name
HAVING COUNT(*) > 1)
ORDER BY last_name + ',' + first_name
我想在 GROUP BY
子句中添加一些内容来比较出生日期。
除了分组,这样的方法对你有用吗?
select * from MyTable a
left join MyTable b
on a.person_id < b.person_id
and a.first_name = b.first_name
and a.last_name = b.last_name
and (
a.birthdate = b.birthdate
or a.birthdate = '1900-1-1'
or b.birthdate = '1900-1-1'
)
它匹配姓氏和名字匹配的行,并且生日匹配或一个生日是您的占位符值。联接的 person_ID 部分删除了重复项(例如,1 匹配到 2,然后是另一行,其中 2 匹配到 1,或者 1 匹配到 1)。
您可能希望扩大名称的匹配标准以查看前几个字符或使用 SOUNDEX
,但您的匹配可能需要更多的手动排序作为最后一步。
编辑:为了 return 在 table 中可能重复的所有记录的列表,与其匹配项无关,请改用此列表:
select distinct a.* from MyTable a
inner join MyTable b
on a.person_id <> b.person_id
and a.first_name = b.first_name
and a.last_name = b.last_name
and (
a.birthdate = b.birthdate
or a.birthdate = '1900-1-1'
or b.birthdate = '1900-1-1'
)
order by a.first_name, a.last_name, a.birthdate
如果日期等于 1/1/1900,您可以使用 nullif 函数 return 空值,因为 nullif(Birthday,'1/1/1900')
对您有利。
此查询可以让您开始查看所有记录及其可能的匹配项:
select p1.person_id
from core_person p1
join core_person p2
on p1.person_id <> p2.person_id
and LEFT(p1.first_name,5) = LEFT(p2.first_name,5)
and LEFT(p1.last_name,5) = LEFT(p2.last_name,5)
and isnull(nullif(p1.Birthday,'1/1/1900'), p2.Birthday) = isnull(nullif(p2.Birthday,'1/1/1900'), p1.Birthday)
group by p1.person_id
如果其中一个生日等于 1/1/1900,它会将生日与自身进行比较,否则它只会在两个记录中的生日相等时加入。
如果您不想看到您的匹配项,您可以使用上述查询的变体作为子查询 return 只有重复的 id 值:
select core_person
from core_person
where person_id in
(
select p1.person_id
from core_person p1
join core_person p2
on p1.person_id <> p2.person_id
and LEFT(p1.first_name,5) = LEFT(p2.first_name,5)
and LEFT(p1.last_name,5) = LEFT(p2.last_name,5)
and isnull(nullif(p1.Birthday,'1/1/1900'), p2.Birthday) = isnull(nullif(p2.Birthday,'1/1/1900'), p1.Birthday)
group by p1.person_id
)