【问题标题】:Find Duplicates By Created Date TSQL按创建日期 SQL 查找重复项
【发布时间】:2014-01-29 03:28:57
【问题描述】:

我正在尝试在单个表中查找重复项,其中至少有一个重复项是在最后一天创建的。

这是我的查询:

SELECT DateOfBirth DOB, 
    FirstName FirstName, 
    LastName LastName, 
    COUNT(*) TotalCount
FROM TABLE
WHERE DateOfBirth IS NOT NULL
    AND DATEDIFF(d,dateCreated,getDate()) <= 1
GROUP BY DateofBirth, FirstName, LastName
HAVING COUNT(*) > 1
ORDER BY COUNT(*) DESC

问题是这个查询没有返回任何内容,因为这两个副本都需要在最后一天创建(读取方式)。

我做了一些测试,发现这个 datediff 要求 dateCreated 列都在 datediff 内。

有什么方法可以把这些重复的最近的重复在最后一天创建的地方带回来?即使最旧的副本是在一年前创建的?

【问题讨论】:

  • and datecreated >= dateadd(d,-1,getdate())
  • 不幸的是,@drewlander,这也是同样的事情。它要求两条记录都在最后一天内创建。
  • 也许分区上的行号会起作用。我会一起检查 row_number 是否为 1,然后在派生表中包含相同的逻辑。
  • 您需要同时查看它们,还是只查看新的副本就足够了?

标签: sql sql-server


【解决方案1】:
;WITH x AS 
(
  SELECT FirstName, LastName, DateOfBirth, DateCreated, 
    TotalCount = COUNT(*) OVER
    (
      PARTITION BY FirstName, LastName, DateOfBirth
    )
  FROM dbo.[TABLE]
)
SELECT FirstName, LastName, DateOfBirth, DateCreated, TotalCount
  FROM x 
  WHERE TotalCount > 1 
  AND DateCreated >= DATEADD(DAY, -1, CURRENT_TIMESTAMP);

如果您想消除那些在最后一天错误创建的重复项,只需将外部查询更改为:

;WITH x AS 
(
  ...
)
DELETE x WHERE TotalCount > 1 
  AND DateCreated >= DATEADD(DAY, -1, CURRENT_TIMESTAMP);

【讨论】:

  • 我想你想在你的分区中为 dateCreated 添加一个 ORDER BY 以确保你的最低行是最旧的记录。
  • @drewlander 这不是 row_number(),顺序无关。将返回在过去 24 小时内创建的所有具有欺骗性的行(不仅仅是最后一行)。
  • 正确。如果他只想要副本,则不应使用计数。如果他想要两个记录,那么它应该。
  • @drewlander 我不确定我是否理解你关于为什么在这两种情况下都不应使用 count 的论点。如果他想要多行(最近的副本和旧版本),他可以省略与 DateCreated 相关的 where 子句。
  • 我的理解是,如果他有 3 条记录并且在过去 24 小时内没有重复记录,那么他不想要它。如果他在过去 24 小时内有 3 条重复记录,那么他希望从原始行开始创建两条记录。这就是为什么 row_number 很重要,如果是这样的话。
【解决方案2】:

我已将其修改为 Aarons 答案的替代方案,以防您只想查看不是原始记录的重复项。

   ;WITH x AS 
    (
      SELECT FirstName, LastName, DateOfBirth, DateCreated, 
         Row_number() OVER
        (
          PARTITION BY FirstName, LastName, DateOfBirth
        order by dateCreated) as rowNumber
      FROM dbo.[TABLE1]
    )
    SELECT FirstName, LastName, DateOfBirth, DateCreated, rowNumber
      FROM x 
      WHERE rowNumber > 1 
      AND DateCreated >= DATEADD(DAY, -1, CURRENT_TIMESTAMP); 

【讨论】:

  • 由于 COUNT(*) 行,我收到 Msg 8120 错误。除非您还使用 GROUP BY,否则您不能将其包含在内部查询中。
  • @aaron-bertrand,我没有测试它,只是在运行中写的。你赢了这个;-)
  • 不试图赢得任何东西,只是提供改进答案并使其正确的建议。
  • 谢谢@Aaron-bertrand。我根据 OP 的需要添加了这个答案作为替代方案。
  • 如前所述,我对此表示赞同,因为它也会有所帮助。我希望我能接受这两个答案,感谢所有帮助。
【解决方案3】:

如果您只需要查看最新的,您可以通过简单的自加入来摆脱困境:

SELECT t2.*
FROM table t1
INNER JOIN table t2 on t1.DateofBirth = t2.DateofBirth and t1.FirstName = t2.FirstName and t1.Lastname = t2.LastName
WHERE t2.DateCreated <> t1.DateCreated 
   AND t2.DateCreated > DATEADD(d, -1, current_timestamp)

如果您需要查看记录的每个 实例,您可以尝试将t1t2 值都放在上面查询的选择列表中。如果您希望它们作为单独的记录,您可以将上述查询作为派生表加入:

SELECT t3.* 
FROM Table t3
INNER JOIN (
    SELECT t2.DateofBirth, t2.FirstName, t2.LastName
    FROM table t1
    INNER JOIN table t2 on t1.DateofBirth = t2.DateofBirth and t1.FirstName = t2.FirstName and t1.Lastname = t2.LastName
    WHERE t2.DateCreated <> t1.DateCreated 
       AND t2.DateCreated > DATEADD(d, -1, current_timestamp)
) sub on t3.DateofBirth = sub.DateofBirth and t3.FirstName = sub.FirstName and t3.Lastname = sub.LastName

【讨论】:

  • 请注意,这种模式需要两次扫描而不是一次,并且通常不是线性扩展而是指数级扩展(随着表变大,处理自联接需要的时间越来越长)。
【解决方案4】:

这应该可以工作,无需使用 CTE:

SELECT 
     DOB =          t.DateOfBirth
    ,FirstName =    t.FirstName
    ,LastName =     t.LastName
    ,TotalCount =   COUNT(*)

FROM 
    TABLE t
WHERE   
    (NOT t.DateOfBirth IS NULL)
    AND EXISTS
       (
        SELECT * 
        FROM 
            TABLE nt 
        WHERE 
            DATEDIFF(d,nt.dateCreated,getDate()) <= 1 
            AND nt.FirstName = t.FirstName 
            AND nt.LastName = t.LastName
            AND nt.DateOfBirth = t.DateOfBirth
        )
GROUP BY 
    t.DateofBirth
    ,t.FirstName
    ,t.LastName
HAVING 
    COUNT(*) > 1
 ORDER BY 
    COUNT(*) DESC

【讨论】:

  • CTE 有什么问题?你对他们有反感吗?也许你的意思是有一个反对 recursive CTE?
  • 老实说,我什至无法执行此代码。我创建了一个模拟表,首先注意到 dateofbirth 后的额外逗号,然后还有其他问题。
  • 另外,这里有语法错误(第 2 行的额外逗号,所有 t.* 实例都不会解析,因为那是无效的)。另请注意,必须执行两次完整扫描(或者我们不知道的任何索引支持的任何操作),并且将此查询更改为可以发出删除欺骗的查询并不容易。
  • 这是我的另一个顾虑。转换为删除不容易。
  • 旧版本的 T-SQL 不支持 CTE。该问题并未指明他使用的是哪个版本的 T-SQL。
猜你喜欢
  • 2021-12-07
  • 1970-01-01
  • 2019-12-06
  • 1970-01-01
  • 2016-04-23
  • 2013-03-23
  • 2016-09-29
  • 2023-03-17
  • 2014-06-04
相关资源
最近更新 更多