One way is to add an index with the column you want to keep as single by adding the clause IGNORE
that will delete possible errors and warnings and delete lines that do not obey the created index:
ALTER IGNORE TABLE creditos
ADD UNIQUE INDEX idx_creditos (usuario_id, status);
ALTER TABLE
...
IGNORE
is the MySQL
Extension to standard SQL
. It Controls how ALTER TABLE
Works if there are Duplicates on Unique Keys in the new table or if warnings occur when Strict mode is enabled. If IGNORE
is not specified, the copy is aborted and Rolled back if Duplicate-key errors occur. If IGNORE
is specified, only the first Row is used of Rows with Duplicates on a Unique key, The other Conflicting Rows are Deleted. Incorrect values are truncated to the Closest matching acceptable value.
...
Or in free translation:
...
IGNORE
is an extension of MySQL
to SQL
standard. It controls how the ALTER TABLE
works if there are duplicates in unique keys in the new table or if any warning happens when the strict mode is enabled. If the IGNORE
is not specified, the copy is aborted and undone if duplicate key errors occur. If IGNORE
if specified, only the first line is used for lines with duplicated keys in single keys. The other conflicting lines will be deleted. Incorrect values are "truncated" to the nearest acceptable value.
...
Another method is to use the DELETE
to delete duplicate lines.
First you have to link the table to itself according to the desired column. You can do this directly in the clause FROM
or with a JOIN
:
FROM creditos c1,
creditos c2
...
WHERE c1.usuario_id = c2.usuario_id
AND c1.status = c2.status
or
...
FROM creditos c1
INNER JOIN c2 ON c1.usuario_id = c2.usuario_id
AND c1.status = c2.status
Soon after this indicate what will be the criterion to delete the record, for example, if you want to select and delete the records with higher id
. Add the clause AND
(considering the first example):
...
AND c1.id > c2.id
For the second example:
...
WHERE c1.id > c2.id
If you want to select and delete children’s id
, respectively we would have:
...
AND c1.id < c2.id
and
...
WHERE c1.id < c2.id
Now we will add the attribute that will filter the record, according to your example:
...
AND c.status = 0
Applying the steps described above
If you want to select and delete the minor record id
:
DELETE c1
FROM creditos c1,
creditos c2
WHERE c1.id > c2.id
AND c1.usuario_id = c2.usuario_id
AND c1.status = c2.status
AND c1.status = 0;
Resulting in (see working on DB Fiddle):
| id | usuario_id | status |
| --- | ---------- | ------ |
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 3 | 5 | 0 |
| 6 | 15 | 0 |
| 10 | 17 | 0 |
Or using INNER JOIN
:
DELETE c1
FROM creditos c1
INNER JOIN creditos c2 ON c1.usuario_id = c2.usuario_id
AND c1.status = c2.status
WHERE c1.id > c2.id
AND c1.status = 0;
Resulting in (see working on DB Fiddle):
| id | usuario_id | status |
| --- | ---------- | ------ |
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 3 | 5 | 0 |
| 6 | 15 | 0 |
| 10 | 17 | 0 |
If you want to select and delete the major record id
:
DELETE c1
FROM creditos c1,
creditos c2
WHERE c1.id < c2.id
AND c1.usuario_id = c2.usuario_id
AND c1.status = c2.status
AND c1.status = 0;
Resulting in (see working on DB Fiddle):
| id | usuario_id | status |
| --- | ---------- | ------ |
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 5 | 5 | 0 |
| 9 | 15 | 0 |
| 10 | 17 | 0 |
Or using INNER JOIN
:
DELETE c1
FROM creditos c1
INNER JOIN creditos c2 ON c1.usuario_id = c2.usuario_id
AND c1.status = c2.status
WHERE c1.id < c2.id
AND c1.status = 0;
Resulting in (see working on DB Fiddle):
| id | usuario_id | status |
| --- | ---------- | ------ |
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 5 | 5 | 0 |
| 9 | 15 | 0 |
| 10 | 17 | 0 |
Observing: To test the data before erasing, you can use SELECT c1.*
instead of DELETE c1
in the examples cited above.
References:
Uses the
having
.– Diego Souza
With the
HAVING
will delete everything, no?– Wallace Maxters
What version of Mysql?
– Leandro Amorim