【问题标题】:How to remove duplicate records based on a value from a different column in MySQL?如何根据 MySQL 中不同列的值删除重复记录?
【发布时间】:2018-03-18 16:57:48
【问题描述】:

我有几个 SQL 表的查询:

我想从列 id 具有多个相同值的查询结果中过滤重复项。在此示例中,我们可以看到 (firstname Miriam) 有两个 id = 1。这里我想保留 pcs = 2 的记录,Miriam 的第二条记录我不想在查询结果中出现。在过滤的情况下,键将基于 pcs 列的值。

我怎样才能做到这一点?我的查询是:

SELECT 
`periode_class_members`.`id`, 
`classes`.`id` AS `class`, 
`periode_class_members`.`periode`, 
`user`.`firstname` AS `firstname`, 
`user`.`lastname` AS `lastname`, 
`periode_class_members`.`status`,
`periode_class_subjects`.`id` AS pcs 
FROM `periode_class_subject_members` 
LEFT JOIN `periode_class_members` 
ON periode_class_subject_members.periode_class_member = periode_class_members.id 
RIGHT JOIN `periode_class_subjects` 
ON periode_class_subject_members.periode_class_subject = periode_class_subjects.id 
JOIN `classes` 
ON periode_class_members.class = classes.id 
LEFT JOIN `user` 
ON periode_class_members.user = user.id
where `classes`.`id` = 1;

【问题讨论】:

  • 对于其他ID,您想保留哪些电脑?为此,您需要指定要保留的规则。
  • 不重复pcs不同
  • "我有一个 SQL 表"??您的查询有 5 个表,结合了非常笨拙的外连接组合。
  • 如果逻辑由程序而不是数据库完成,程序将不得不循环遍历不同的 id 值,对于每个 id 获取该 id 的所有记录,循环遍历记录直到它有决定了它想要对哪条记录进行操作,然后用那条记录做它的事情。
  • “逻辑是由程序完成的,而不是由数据库完成的。” 所以 DBMS 忽略了规则。 DBMS 怎么可能删除不需要的记录,却不知道哪些需要哪些不需要?这是没有意义的。似乎 Binarus 已经给了你上面唯一正确的答案。想想这个。由于显而易见的原因,您请求的内容无法完成,因此您可能希望完全删除您的请求。

标签: mysql sql select join duplicates


【解决方案1】:

SQL - 没有视图

SELECT *
FROM 
(<<your query>>) AS sub1
WHERE NOT EXISTS
 (SELECT *
  FROM
  (<<your query>>) AS sub2
  WHERE id = sub1.id
    AND pcs <> sub1.pcs
    AND pcs = 2);

...在两个地方都插入了&lt;&lt;your query&gt;&gt; - 为简洁起见,此处省略。

SQL - 带视图

与上面类似,但查询只需要插入一次:

CREATE VIEW vw_unfiltered_query AS
<<your query>>;

CREATE VIEW vw_filtered_query AS
SELECT *
FROM vw_unfiltered_query AS sub1
WHERE NOT EXISTS
 (SELECT *
  FROM vw_unfiltered_query AS sub2
  WHERE id = sub1.id
    AND pcs <> sub1.pcs
    AND pcs = 2);

演示

以下演示显示了使用上述两种方法进行过滤之前和之后的结果。 (为简单起见,它使用来自预填充表的简单 SELECT 语句代替您的查询。)

http://rextester.com/MXZDDJ39435

说明

WHERE NOT EXISTS 确保仅包含具有相同 id 但不同 pcs 值等于 2 的另一行的行。

【讨论】:

  • 伟大的解决方案史蒂夫!不是很容易,但是通过这种方法它可以工作!最后一行, pcs 2 我必须采用 pcs = 2 才能获得正确的结果。感谢您也为您的解决方案提供了 rextester!
  • 谢谢佩里诺。起初我有点困惑,但后来意识到NOT EXISTS 需要删除 pcs &lt;&gt; 2 的重复行 - 所以为了做到这一点,它实际上需要找到一个不同的 pcs = 2 的重复项集中的行。已更新答案并在演示中添加了更多行以显示它适用于 > 2 个重复项。
【解决方案2】:

有几种技术。关键是首先有一个过滤的唯一结果列表,然后添加导致问题的列。 (附附规则)。

您可以下载子查询中的人员列表并稍后附加角色,您可以下载子查询中的角色 (1),也可以将子查询中的角色分组 (2)。

所以你可以:

SELECT 
`periode_class_members`.`id`, 
`classes`.`id` AS `class`, 
`periode_class_members`.`periode`, 
`user`.`firstname` AS `firstname`, 
`user`.`lastname` AS `lastname`, 
`periode_class_members`.`status`,
(SELECT min(`periode_class_subjects`.`id`) FROM periode_class_subjects WHERE periode_class_subject_members.periode_class_subject = periode_class_subjects.id GROUP BY `periode_class_subjects`.`id`) AS pcs 
FROM `periode_class_subject_members` 
LEFT JOIN `periode_class_members` 
ON periode_class_subject_members.periode_class_member = periode_class_members.id 
RIGHT JOIN `periode_class_subjects` 
JOIN `classes` 
ON periode_class_members.class = classes.id 
LEFT JOIN `user` 
ON periode_class_members.user = user.id
where `classes`.`id` = 1;

或者(非常糟糕的例子,不要在生产中这样做)

SELECT 
`periode_class_members`.`id`, 
`classes`.`id` AS `class`, 
`periode_class_members`.`periode`, 
`user`.`firstname` AS `firstname`, 
`user`.`lastname` AS `lastname`, 
`periode_class_members`.`status`,
min(`periode_class_subjects`.`id`) AS pcs 
FROM `periode_class_subject_members` 
LEFT JOIN `periode_class_members` 
ON periode_class_subject_members.periode_class_member = periode_class_members.id 
RIGHT JOIN `periode_class_subjects` 
ON periode_class_subject_members.periode_class_subject = periode_class_subjects.id 
JOIN `classes` 
ON periode_class_members.class = classes.id 
LEFT JOIN `user` 
ON periode_class_members.user = user.id
where `classes`.`id` = 1
group by `periode_class_members`.`id`, 
`classes`.`id` , 
`periode_class_members`.`periode`, 
`user`.`firstname`, 
`user`.`lastname` , 
`periode_class_members`.`status`;

我建议拓宽子查询的知识。

【讨论】:

    【解决方案3】:
    SELECT  pcm.`id`,
            c.`id` AS `class`,
            pcm.`periode`,
            u.`firstname`, u.`lastname`,
            pcm.`status`,
            MIN(pcs.`id`) AS pcs
        FROM  `periode_class_subject_members` AS pcsm
        LEFT JOIN  `periode_class_members` AS pcm
              ON pcsm.periode_class_member = pcm.id
        RIGHT JOIN  `periode_class_subjects` AS pcs
               ON pcsm.periode_class_subject = pcs.id
        JOIN  `classes` AS c  ON pcm.class = c.id
        LEFT JOIN  `user` AS u  ON pcm.user AS u = u.id
        where  c.`id` = 1
        GROUP BY  pcm.`id`, c.`id`,
                  pcm.`periode`,
                  u.`firstname`,
                  u.`lastname`, pcm.`status` ;
    

    两个实质性的变化是MIN和添加GROUP BY

    如果MIN 不是正确的算法,则换成其他算法。

    GROUP BY 列表与SELECT 中的其余列相同。

    我冒昧地为每个表提供了较短的别名。

    【讨论】:

    • SQL MIN() 语句我不能使用,因为剩余的 pcs.id 并不总是最小值。 pcs.id 将由调用 SQL 查询的程序函数给出,并且 pcs.id 总是可以不同的。在此示例中,pcs.id 也可以是更高的值。下一次 Miriam Finders pcs 可能是 6。这取决于之前在程序过程中选择的基础值。
    • 请详细说明“在程序选择前”。如果不了解 which pcs.id,我们将无法完成对您的问题的帮助。
    【解决方案4】:

    如果 pcs 字段的最小值为 2 是事实,那么下面的查询应该可以完成工作。

    select id,class,periode,firstname,lastname,status,(Select pcs from unfiltered un
        where un.id = unfiltered.id
        order by pcs limit 1) as pcs 
    from 
    (your query)
    group by id;
    

    上述查询运行成功。我没有添加您的查询来让您了解我使用的逻辑。请查看演示here

    现在,我将在上述解决方案中添加您的查询,并相应地修改列名。

    Select temp.id,temp.class,temp.periode,
           temp.firstname,temp.lastname,temp.status,
           (Select pcs from temp t
               where t.id = temp.id
            order by t.pcs limit 1) as pcs 
    from 
       (SELECT 
    `periode_class_members`.`id` AS id, 
    `classes`.`id` AS `class`, 
    `periode_class_members`.`periode`, 
    `user`.`firstname` AS `firstname`, 
    `user`.`lastname` AS `lastname`, 
    `periode_class_members`.`status`,
    `periode_class_subjects`.`id` AS pcs 
    FROM `periode_class_subject_members` 
    LEFT JOIN `periode_class_members` 
    ON periode_class_subject_members.periode_class_member = periode_class_members.id 
    RIGHT JOIN `periode_class_subjects` 
    ON periode_class_subject_members.periode_class_subject = periode_class_subjects.id 
    JOIN `classes` 
    ON periode_class_members.class = classes.id 
    LEFT JOIN `user` 
    ON periode_class_members.user = user.id
    where `classes`.`id` = 1) as temp
    group by temp.id;
    

    希望它有效!

    【讨论】:

    • 你试过查询吗?是否按预期工作?
    猜你喜欢
    • 1970-01-01
    • 2021-01-10
    • 2021-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-21
    • 2010-10-14
    相关资源
    最近更新 更多