sql - repetir - ¿Cómo puedo eliminar una de las dos filas perfectamente idénticas?
no repetir registros en consulta sql (13)
Estoy limpiando una tabla de base de datos sin una clave principal (lo sé, lo sé, ¿en qué estaban pensando?). No puedo agregar una clave principal, porque hay un duplicado en la columna que se convertiría en la clave. El valor duplicado proviene de una de las dos filas que son idénticas en todos los aspectos. No puedo eliminar la fila a través de una GUI (en este caso MySQL Workbench, pero estoy buscando un enfoque independiente de la base de datos) porque se niega a realizar tareas en tablas sin claves principales (o al menos una columna NQ de NQ), y No puedo agregar una clave principal, porque hay un duplicado en la columna que se convertiría en la clave. El valor duplicado proviene de uno ...
¿Cómo puedo eliminar uno de los gemelos?
Agregué una columna Guid a la tabla y la configuré para generar un nuevo ID para cada fila. Entonces podría eliminar las filas utilizando una GUI.
En PostgreSQL hay una columna implícita llamada ctid
. Ver el wiki . Así que eres libre de usar lo siguiente:
WITH cte1 as(
SELECT unique_column, max( ctid ) as max_ctid
FROM table_1
GROUP BY unique_column
HAVING count(*) > 1
), cte2 as(
SELECT t.ctid as target_ctid
FROM table_1 t
JOIN cte1 USING( unique_column )
WHERE t.ctid != max_ctid
)
DELETE FROM table_1
WHERE ctid IN( SELECT target_ctid FROM cte2 )
No estoy seguro de qué tan seguro es usar esto cuando existe la posibilidad de actualizaciones simultáneas. Por lo tanto, puede ser sensato hacer una LOCK TABLE table_1 IN ACCESS EXCLUSIVE MODE;
Antes de hacer realmente la limpieza.
En caso de que pueda agregar una columna como
ALTER TABLE yourtable ADD IDCOLUMN bigint NOT NULL IDENTITY (1, 1)
hazlo
luego cuente las filas agrupadas por su columna de problemas donde cuente> 1, esto identificará sus gemelos (o trillizos o lo que sea).
luego seleccione la columna de problemas donde su contenido sea igual al contenido identificado arriba y verifique las ID en IDCOLUMN.
borre de su tabla donde IDCOLUMN es igual a uno de esos ID.
En mi caso, podría obtener la GUI para que me proporcione una cadena de valores de la fila en cuestión (como alternativa, podría haberlo hecho a mano). A sugerencia de un colega, en cuya deuda permanezco, utilicé esto para crear una declaración INSERT:
INSERT
''ID1219243408800307444663'', ''2004-01-20 10:20:55'', ''INFORMATION'', ''admin'' (...)
INTO some_table;
Probé la declaración de inserción, por lo que ahora tenía trillizos. Finalmente, ejecuté un simple BORRAR para eliminarlos todos ...
DELETE FROM some_table WHERE logid = ''ID1219243408800307444663'';
seguido de INSERT una vez más, dejándome con una sola fila y las brillantes posibilidades de una clave principal.
Esto funciona para PostgreSQL
DELETE FROM tablename WHERE id = 123 AND ctid IN (SELECT ctid FROM tablename WHERE id = 123 LIMIT 1)
Esto se puede lograr usando un CTE y la función ROW_NUMBER()
, como se muestra a continuación:
/* Sample Data */
CREATE TABLE #dupes (ID INT, DWCreated DATETIME2(3))
INSERT INTO #dupes (ID, DWCreated) SELECT 1, ''2015-08-03 01:02:03.456''
INSERT INTO #dupes (ID, DWCreated) SELECT 2, ''2014-08-03 01:02:03.456''
INSERT INTO #dupes (ID, DWCreated) SELECT 1, ''2013-08-03 01:02:03.456''
/* Check sample data - returns three rows, with two rows for ID#1 */
SELECT * FROM #dupes
/* CTE to give each row that shares an ID a unique number */
;WITH toDelete AS
(
SELECT ID, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY DWCreated) AS RN
FROM #dupes
)
/* Delete any row that is not the first instance of an ID */
DELETE FROM toDelete WHERE RN > 1
/* Check the results: ID is now unique */
SELECT * FROM #dupes
/* Clean up */
DROP TABLE #dupes
Tener una columna para ORDER BY es útil, pero no es necesario a menos que tenga una preferencia para cuál de las filas eliminar. Esto también manejará todas las instancias de registros duplicados, en lugar de forzarlo a eliminar una fila a la vez.
Intentado LIMIT 1? Esto solo eliminará 1 de las filas que coincidan con su consulta DELETE
DELETE FROM `table_name` WHERE `column_name`=''value'' LIMIT 1;
Para PostgreSQL puedes hacer esto:
DELETE FROM tablename
WHERE id IN (SELECT id
FROM (SELECT id, ROW_NUMBER()
OVER (partition BY column1, column2, column3 ORDER BY id) AS rnum
FROM tablename) t
WHERE t.rnum > 1);
column1, column2, column3 sería el conjunto de columnas que tienen valores duplicados.
Referencia here .
Podrías usar un max, lo cual era relevante en mi caso.
DELETE FROM [table] where id in
(select max(id) from [table] group by id, col2, col3 having count(id) > 1)
Asegúrese de probar sus resultados primero y tener una condición limitante en su "tener" cláusula. Con una consulta de eliminación tan grande, es posible que desee actualizar su base de datos primero.
Tenga en cuenta que MySQL tiene su propia extensión de DELETE
, que es DELETE ... LIMIT
, que funciona de la forma habitual que se esperaría de LIMIT
: http://dev.mysql.com/doc/refman/5.0/en/delete.html
La opción LIMIT row_count de MySQL específica para DELETE le dice al servidor el número máximo de filas que se eliminarán antes de que el control se devuelva al cliente. Esto se puede usar para asegurar que una declaración DELETE determinada no tome demasiado tiempo. Simplemente puede repetir la instrucción DELETE hasta que el número de filas afectadas sea menor que el valor LIMIT.
Por lo tanto, puede usar DELETE FROM some_table WHERE x="y" AND foo="bar" LIMIT 1;
tenga en cuenta que no hay una forma sencilla de decir "eliminar todo excepto uno"; simplemente verifique si todavía tiene duplicados de fila.
Una opción para resolver su problema es crear una nueva tabla con el mismo esquema y luego hacer:
INSERT INTO new_table (SELECT DISTINCT * FROM old_table)
y luego simplemente renombrar las tablas.
Por supuesto, necesitará aproximadamente la misma cantidad de espacio que su tabla necesita en su disco para hacer esto.
No es eficiente, pero es increíblemente simple.
delete top (1) funciona en Microsoft SQL Server (T-SQL).
SET ROWCOUNT 1
DELETE FROM [table] WHERE ....
SET ROWCOUNT 0
Esto solo eliminará una de las dos filas idénticas