【问题标题】:Find duplicate emails in MySql and delete certain ones based on conditions在 MySql 中查找重复的电子邮件并根据条件删除某些电子邮件
【发布时间】:2014-12-29 17:23:30
【问题描述】:

我看到了很多查找重复记录并删除它们的方法,但我找不到我要查找的方法,即根据特定条件删除它们。

下面的第一个 SQL 代码取自另一篇文章,非常适合定位重复项。但是,我对第二部分有疑问。

<cfquery datasource="mydatabase" name="duplist">
SELECT  a.*, b.totalCount AS Duplicate
FROM    mytable a
        INNER JOIN
        (
            SELECT  email, COUNT(*) totalCount
            FROM    mytable
            GROUP   BY email
            HAVING  COUNT(*) > 1
        ) b ON a.email = b.email
</cfquery>

<cfoutput query="duplist">
    <CFQUERY DATASOURCE="mydatabase" name="dlist">
    SELECT * FROM mytable
    WHERE userid = '#userid#'
    AND activedate is null
    </CFQUERY>
</cfoutput> 

<cfoutput>
Total To Be Deleted: #dlist.recordcount#
</cfoutput>

我正在尝试使用 SELECT(在将其替换为 DELETE 之前)仅根据输出查询“duplist”和重复的电子邮件记录,那些没有“活动日期”的重复用户电子邮件。我只得到一条记录(在#dlist.recordcount# 中),这是最后一条记录!查询不应该遍历它们吗?

已编辑:

经过一些反馈并检查记录计数不正确,因为它在循环之外。它将在没有 startdate 的情况下检索这些记录。但是,现在真正的问题在于以下场景:

ID   USERID   EMAIL          STARTDATE
1    user1    test@test.com 
2    user2    test@test.com  11/01/2014
3    user3    test@test.com 
4    user4    test@test.com  11/02/2014 
5    user5    me@mydomain.com
6    user6    me@mydomain.com

运行上面的代码会列出这6条重复邮件的记录。第二个查询将选择(删除)那些没有开始日期的,即记录 1、3、5 和 6。两个问题:

  1. 记录 1 和 3 将被删除,但记录 2 和 4 仍然重复
  2. 记录 5 和 6 将被删除,我的电子邮件中没有用户。我需要保留其中一个。

如何修改代码以应对场景?我想保留记录 #4 和 #6,因为 4 比 2 新,而 6 比 6 新。

4    user4    test@test.com  11/02/2014 
6    user6    me@mydomain.com

【问题讨论】:

  • 这是cfoutput 的正确行为。如果要查看所有记录,则一一查看;将最后一条语句&lt;cfoutput&gt;Total To Be Deleted: #dlist.recordcount# &lt;/cfoutput&gt; 移动到&lt;cfoutput query="duplist"&gt;&lt;cfquery&gt;....&lt;/cfquery&gt;&lt;/cfoutput&gt;。您将看到预期的输出n 次数。
  • 它可能会在那里循环,但是第二个查询有一个条件。把它放在那里不会正确计算它应该在第二个查询中过滤的内容。
  • 如果你想要正确的计数,你需要在&lt;cfoutput query="duplist"&gt; 中使用一个变量,如果#dlist.recordcount# 大于0,则增加它。
  • 计数可能是错误的,但我真正想要实现的是删除正确的重复记录,该记录具有 activedate null 但代码没有这样做......
  • 预期输出是什么?根据编辑后的数据样本,删除后要保留哪些记录。

标签: mysql sql coldfusion duplicates


【解决方案1】:

您可以使用 Rank() 函数对数据进行排名,并删除未排名为 1 的行。

Oracle 等效于 Rank() 查询以选择 #4 和 #6 数据:

SELECT * FROM
(
SELECT USERNAME, EMAIL, START_DATE, 
        RANK() OVER (PARTITION BY EMAIL ORDER BY START_DATE DESC NULLS LAST, ROWNUM DESC) AS RANK
FROM TEMP_SOL
)
WHERE RANK = 1

可以使用此链接Rank function in MySQL with Order By clause导出Mysql等价物

编辑:非排名解决方案可以是:

首先获取所有重复的电子邮件

<cfquery name="dupEmail" datasource="XXX">
SELECT EMAIL
FROM TEMP_SOL
GROUP BY EMAIL
HAVING COUNT(*) > 1
</cfquery>

循环通过 dupEmail 和

  1. 选择不需要删除的用户名。
  2. 选择/删除不等于上述用户名但具有相同emailid的用户名。

    <cfloop query="dupEmail">
       <cfquery name="UserToRetain" datasource="XXX">
           SELECT USERNAME FROM TEMP_SOL
           WHERE EMAIL = '#dupEmail.Email#'
           ORDER BY START_DATE DESC NULLS LAST, ROWNUM DESC
           LIMIT 1 
      </cfquery>
    
      <cfquery name="DeleteUsers" datasource="XXX">
             SELECT * FROM TEMP_SOL
             WHERE USERNAME <> '#UserToRetain.USERNAME#' AND EMAIL='#dupEmail.Email#'
      </cfquery>
    
    </cfloop>
    

注意:以上代码未经测试,查询可能无法在 mysql 上运行。

【讨论】:

  • 我是MySql的新手:(否则我不会遇到这些问题。有没有可能看到它在MySql中是如何完成的?
  • 对不起伙计,我的机器上没有安装 mysql 实例。看mysql“rank function”链接,可能没有你想的那么难。
  • 无法显示排名。它没有检索到正确的号码。我想输入第一个查询的结果。
  • 添加了一个可能有用的非排名解决方案。 LIMIT 1 是我为 mysql 添加的唯一位,但不确定它是否按预期运行。
  • ...WHERE RANK 1 ORDER BY email, id desc;它导致错误 Unknown column 'rank' in 'where clause' 不确定这将如何解决重复记录问题...
【解决方案2】:


您可以在查询中使用 IN 子句。但首先,您需要创建一个要传递给第二个查询的 userId 列表。您可以像这样使用valueList 来做到这一点

<cfset userIdList = valueList(duplist.userId) />

然后像这样在查询中传递该列表

<CFQUERY DATASOURCE="mydatabase" name="dlist">
    SELECT * FROM myTable WHERE userId IN (#userIdList#) AND activeDate is null
<CFQUERY>

【讨论】:

  • 代码不起作用....执行数据库查询时出错。您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册以获取正确的语法使用...我也对使用 IN 非常谨慎。还有其他解决方案用于使用 IN 使用嵌套 SQL 查找重复项。我跑的时候,效率太低了,每次都crash!
  • @Jack,这段代码应该可以工作。你有没有像这样上面的查询 用CFOUTPUT 包装CFQUERY。并且不用担心 IN 子句,IN 子句就足够了,你的嵌套 SQL 逻辑可能有问题。
  • 我做到了。它抛出错误,因为某些用户 id 有 @ 符号。我不知道它为什么这样做。
  • @Jack,我猜你的表有 userids as varchar,而不是 int。如果是这种情况,则在上述代码中使用 QuotedValueList 而不是 valueList
  • 错误诊断显示:执行数据库查询时出错。您的 SQL 语法有错误;查看与您的 MySQL 服务器版本相对应的手册,了解在 'laizhijie'',''baimaolai1'',''baimaolai2'',''fsabeijing'',''pekfsa'',''19900917' 附近使用的正确语法'' at line 1 第 20 行出现错误。第 20 行是您的 SQL 代码:SELECT * FROM myTable WHERE userId IN (#userIdList#) AND activeDate is null
【解决方案3】:

这也可以在单个查询中完成

<CFQUERY DATASOURCE="mydatabase" name="dlist">
 SELECT * FROM myTable 
 WHERE userId IN (SELECT userId
    FROM    mytable 
    GROUP   BY email
    HAVING  COUNT(email) > 1
   ) 
   AND activeDate is null
<CFQUERY>

【讨论】:

  • 就像我在上面的评论中所说的那样。 IN 代码使 mytable 崩溃 :-(
  • 它应该可以正常工作,因为它只是简单的 IN 子句,其中包含子查询。
  • 我希望它会,但它不会。
  • 504 - 网关超时
【解决方案4】:

这是您的原始查询:

SELECT  a.*, b.totalCount AS Duplicate
FROM    mytable a
    INNER JOIN
    (
        SELECT  email, COUNT(*) totalCount
        FROM    mytable
        GROUP   BY email
        HAVING  COUNT(*) > 1
    ) b ON a.email = b.email

你需要做的就是添加:

where a.activeDate is null

你有你的记录。然后,一旦你看到它们,用“删除”这个词替换你的选择子句

编辑从这里开始

由于这仍然会留下重复项,因此在执行上述操作后,请执行以下操作:

select id, email -- can be changed to delete after
from myTable deleteFrom join myTable keep on deleteFrom.email = keep.email
where deleteFrom.id < keep.id

这将保持最新记录。

【讨论】:

  • 这行得通!谢谢丹。但是我选择的记录存在一个潜在的问题。我已经更新了我的问题。请快速浏览。
  • 如果我使用第一个查询删除重复项,我相信这可能会解决问题 1。但问题是即使 activedate 为空,第一个查询也会删除我想要保留的一条记录。所以我仍然会遇到问题2。
  • RE 编辑:where deleteFrom.id &lt; keep.id 这种逻辑应该可以正常工作。 (假设最新的开始日期与最新的“id”相关联)。
猜你喜欢
  • 2023-01-19
  • 1970-01-01
  • 2014-05-15
  • 2015-01-24
  • 2016-08-08
  • 1970-01-01
  • 2013-09-04
  • 1970-01-01
  • 2014-12-21
相关资源
最近更新 更多