【问题标题】:SQL Capture duplicate records across two DIFFERENT columnsSQL 跨两个不同的列捕获重复记录
【发布时间】:2019-02-03 13:52:25
【问题描述】:

我正在使用 MySQL 编写一个异常捕获页面,用于在以下场景中捕获重复的计费条目。

项目详细信息输入到一个包含以下两列(以及其他列)的表中。

ItemCode VARCHAR(50), BillEntryDate DATE

经常会在几天内多次输入同一项目的帐单。喜欢,

"Football","2019-01-02"
"Basketball","2019-01-02"
...
...
"Football","2019-01-05"
"Rugby","2019-01-05"
...
"Handball","2019-01-05"
"Rugby","2019-01-07"
"Rugby","2019-01-10"

在上面的示例中,足球项目计费两次 - 第一次是 1 月 2 日,另一次是 1 月 5 日。同样,项目 Rugby 在 1 月 5 日、7 日、10 日计费三次。

我希望编写简单的 SQL,它可以提取每个项目 [例如,使用 distinct(ItemCode) 子句],然后显示 30 天内重复的所有记录。 在上述情况下,预期的输出应该是以下 5 条记录:

"Football","2019-01-02"
"Football","2019-01-05"
"Rugby","2019-01-05"
"Rugby","2019-01-07"
"Rugby","2019-01-10"

我正在尝试运行以下 SQL:

select * from tablen a, tablen b, where a.ItemCode=b.ItemCode and a.BillEntryDate = b.BillEntryDate+30;

但是,这似乎非常低效,因为它运行了很长时间而不显示任何记录。 是否有可能获得一种不太复杂且速度更快的方法?

我确实探索了现有的主题(如How do I find duplicates across multiple columns?),但它正在捕获两个列具有相同值的重复项。我的要求是一列相同的值,第二列在一个月的日期范围内变化。

【问题讨论】:

    标签: mysql sql


    【解决方案1】:

    你可以使用:

    select t.*
    from tablen t
    where exists (select 1
                  from tablen t2
                  where t2.ItemCode = t.ItemCode and
                        t2.BillEntryDate <> t.BillEntryDate and
                        t2.BillEntryDate >= t1.BillEntryDate - interval 30 day and                    t2.BillEntryDate <= t1.BillEntryDate + interval 30 day 
                 );
    

    这将拾取这对中的两个重复项。

    为了提高性能,您需要在(ItemCode, BillEntryDate) 上建立索引。

    【讨论】:

    • 谢谢@GordonLinoff。但是,这个不起作用。它只是按原样返回所有记录,并且需要 76.5 秒才能完成对具有大约 17K 记录的表的查询执行。服务器管理员不会高兴。 :-) 感谢索引提示,我已经在这两列上建立了索引。
    • @user6337701 。 . .当然,它需要忽略“相同”行。我只是添加了不等式。
    • 这个现在可以工作了,谢谢!虽然它仍然需要很长时间才能运行(超过 3 分钟),这使得在网页上使用起来很复杂。我会看看执行是否可以改进。 +1 并将其标记为答案。我一直在使用以下更快的 NON-sql 方法:生成按 ItemCode、BillEntryDate 排序的所有记录。在excel中转​​储。放公式得到这一行的BillEntryDate - 上一行的BillEntryDate。现在过滤此列以获取 -30 到 +30 范围内的值。虽然是非 sql,但它更快,所以我可能会坚持这个每月一次的活动。
    • @user6337701 。 . .为了获得最佳性能,您需要一个单一的复合索引,如答案中所述。
    【解决方案2】:

    EXISTS:

    select ItemCode, BillEntryDate
    from tablename t
    where exists (
      select 1 from tablename 
      where 
        ItemCode = t.ItemCode  
        and 
        abs(datediff(BillEntryDate, t.BillEntryDate)) between 1 and 30
    )
    

    【讨论】:

    • 谢谢@forpas。据我所知, now() 返回服务器的当前系统日期和时间。查询不限于最近一个月的时间 - 它应该是通用的。无论如何,我通过在 SQL 中的两个实例上将 now() 替换为 t.BillEntryDate 来运行您提供的查询(使用 now() 函数)和另一个修改版本。在这两种情况下,在有 17K 条记录的表上都需要 3 分钟以上,并且显示的输出不正确。
    • 关于 3 分钟我不知道。但至于时间段,我可能误解了。你能解释一下通用部分吗?
    • 通用意味着它不应在今天的 +30 或 -30 天内。似乎 now() 的使用将其限制在该日期范围内。它应该跨越所有时期。
    • 所以您希望重复日期的间隔小于 30 天?
    猜你喜欢
    • 2021-10-13
    • 2015-11-03
    • 1970-01-01
    • 2018-07-10
    • 1970-01-01
    • 2021-11-11
    • 1970-01-01
    • 1970-01-01
    • 2022-12-09
    相关资源
    最近更新 更多