【问题标题】:Is there a way to equate null values to non null values in a partition in SQL?有没有办法将空值等同于 SQL 分区中的非空值?
【发布时间】:2020-12-20 18:38:22
【问题描述】:

我有一个人员记录数据库表,其中包含用户 ID、名字、姓氏、出生日期和电子邮件地址的列。 FirstName、LastName 和 Email 是必需的值,但如果此人未提供该信息,则 DOB 可以为 null,因此有几行可能如下所示:

FirstName          LastName           DOB               Email                      UserID
John               Doe                1990-01-01        johndoe@gmail.com          1
Jane               Doe                1990-02-01        janedoe@gmail.com          2
John               Doe                NULL              johndoe@gmail.com          3
Paul               Blart              1985-01-01        mallcop@gmail.com          4
Clark              Kent               NULL              ImNotSuperman@gmail.com    5
Paul               Blart              1985-01-01        mallcop@gmail.com          6

我正在尝试编写一个查询(这是一个更大程序的一部分)来识别数据库中重复的人员记录。要求是 FirstName、LastName 和 Email 必须相同,如果 DOB 有值则必须相同,但如果为 null,则仍可以标记为重复项。所以在上表中,将选择两个 John Doe 和两个 Paul Blart。我想在分区语句中执行此操作。所以我最初的尝试是:

SELECT  COUNT(UserID) OVER (Partition BY FirstName, LastName, DOB, Email) AS Count,
DENSE_RANK() OVER (ORDER BY FirstName, LastName, DOB, Email) AS RANK,
UserID, FirstName, LastName, DOB, Email
FROM People
where COUNT(UserID) OVER (Partition BY FirstName, LastName, DOB, Email) > 1

正确选择 Paul Blart 为重复项,但不选择 John Doe,因为 DOB 的值为空。有什么办法可以正确选择这些记录吗?

【问题讨论】:

    标签: sql sql-server subquery window-functions


    【解决方案1】:

    这可能用exists表示更简单:

    select t.*
    from mytable t
    where exists (
        select 1
        from mytable t1
        where 
            t1.id <> t.id
            and t1.firstname = t.firstname
            and t1.lastname = t.lastname
            and t1.email = t.email
            and (t1.dob = t.dob or t1.dob is null or t.dob is null)
    )
    

    【讨论】:

      【解决方案2】:

      您可以使用窗口函数来做到这一点:

      select t.*
      from (select t.*,
                   count(*) over (partition by firstname, lastname, email, dob) as cnt,
                   sum(case when dob is null then 1 else 0 end) over (partition by firstname, lastname, email) as cnt_null
            from t
           ) t
      where cnt > 1 or 
            (dob is not null and cnt_null > 0);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-23
        • 2019-09-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-04
        相关资源
        最近更新 更多