首页 > 解决方案 > 删除 MySQL 表中的相同条目

问题描述

我是 MySQL 的初学者。在这里我刚刚创建了一个表

CREATE TABLE Student (
    Rollno int,
    LastName varchar(255),
    FirstName varchar(255),
    Gpa float,
);

创建表后,我在以下查询的帮助下添加了值

USE persons;
INSERT INTO student
VALUES
 (1, 'Aa', 'A', 8.5),
 (2, 'Bb', 'B', 8.6),
 (3, 'Cc', 'C', 8.7),
 (4, 'Dd', 'D', 8.4);

我刚刚运行了两次上述查询,结果有两个条目,如下所示 结果数据库

所以我只想删除重复的条目,结果数据库应该类似于 所需数据库

尽管我搜索并尝试过,但我不具备此答案id中提到的任何独特价值。

我再次尝试在这个答案的帮助下,代码如下所示

WITH cte AS (
    SELECT
        Rollno,
        LastName,
        FirstName,
        Gpa,
        ROW_NUMBER() OVER (
            PARTITION BY
                Rollno
            ORDER BY
                Rollno
        )RN
     FROM
        persons.student
)
DELETE FROM cte
WHERE RN > 1;

但上面抛出错误说明

错误代码:1288。DELETE的目标表cte不可更新

所以我只想要一个最佳解决方案,在表中包含单个条目。

标签: mysqlsql

解决方案


这是我使用您的数据测试的解决方案。感谢您提供一个完整且易于测试的案例!

mysql> alter table student add column id int auto_increment primary key first;
Query OK, 0 rows affected (0.08 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> select * from student;
+----+--------+----------+-----------+------+
| id | Rollno | LastName | FirstName | Gpa  |
+----+--------+----------+-----------+------+
|  1 |      1 | Aa       | A         |  8.5 |
|  2 |      2 | Bb       | B         |  8.6 |
|  3 |      3 | Cc       | C         |  8.7 |
|  4 |      4 | Dd       | D         |  8.4 |
|  5 |      1 | Aa       | A         |  8.5 |
|  6 |      2 | Bb       | B         |  8.6 |
|  7 |      3 | Cc       | C         |  8.7 |
|  8 |      4 | Dd       | D         |  8.4 |
+----+--------+----------+-----------+------+
8 rows in set (0.00 sec)

mysql> delete s1 from student as s1 join student as s2 on s1.rollno=s2.rollno and s1.id > s2.id;
Query OK, 4 rows affected (0.03 sec)

mysql> select * from student;
+----+--------+----------+-----------+------+
| id | Rollno | LastName | FirstName | Gpa  |
+----+--------+----------+-----------+------+
|  1 |      1 | Aa       | A         |  8.5 |
|  2 |      2 | Bb       | B         |  8.6 |
|  3 |      3 | Cc       | C         |  8.7 |
|  4 |      4 | Dd       | D         |  8.4 |
+----+--------+----------+-----------+------+
4 rows in set (0.00 sec)

回复您的评论:

这个查询中的s1ands2通常称为“表别名”,但您应该将它们视为更像别名。它们一次引用一行,因此您可以比较各行中的值。

假设有这样的两行:

+----+--------+----------+-----------+------+
| id | Rollno | LastName | FirstName | Gpa  |
+----+--------+----------+-----------+------+
|  1 |      1 | Aa       | A         |  8.5 |
|  5 |      1 | Aa       | A         |  8.5 |

哪一行可以指示s1,哪一行可以s2使得连接条件为真?

两行具有相同的 Rollno,因此s1.rollno=s2.rollno无论哪种方式都满足连接条件。

一行的ida 值小于另一行,因此s1.id > s2.id要满足连接条件,我们知道这s2是 id 为 1 的第一行,s1是 id 为 5 的第二行。

因此,连接条件的两项共同保证s1s2将引用具有相同 Rollno 的两行,并且s2将具有较小的id值。

+----+--------+----------+-----------+------+
| id | Rollno | LastName | FirstName | Gpa  |
+----+--------+----------+-----------+------+
|  1 |      1 | Aa       | A         |  8.5 | <-- s2
|  5 |      1 | Aa       | A         |  8.5 | <-- s1

我们希望保留 id 值较小的“第一”行 ( s2),并删除另一行 ( s1)。因此delete s1 from .... 在 MySQL 的多表删除语法中,您指定将在from关键字之前删除哪一行。from子句 ( )中定义的其他行别名s2不会被删除。


推荐阅读