Si agregar una clave principal no es una opción, entonces un enfoque sería almacenar los duplicados DISTINCT en una tabla temporal, eliminar todos los registros duplicados de la tabla existente y luego agregar los registros nuevamente a la tabla original desde la tabla temporal .
Por ejemplo (escrito para SQL Server 2008, pero la técnica es la misma para cualquier base de datos):
DECLARE @original AS TABLE([hash] varchar(20), [d] float)
INSERT INTO @original VALUES('A', 1)
INSERT INTO @original VALUES('A', 2)
INSERT INTO @original VALUES('A', 1)
INSERT INTO @original VALUES('B', 1)
INSERT INTO @original VALUES('C', 1)
INSERT INTO @original VALUES('C', 1)
DECLARE @temp AS TABLE([hash] varchar(20), [d] float)
INSERT INTO @temp
SELECT [hash], [d] FROM @original
GROUP BY [hash], [d]
HAVING COUNT(*) > 1
DELETE O
FROM @original O
JOIN @temp T ON T.[hash] = O.[hash] AND T.[d] = O.[d]
INSERT INTO @original
SELECT [hash], [d] FROM @temp
SELECT * FROM @original
No estoy seguro de si sqlite tiene una ROW_NUMBER()
función de tipo, pero si la tiene, también puede probar algunos de los enfoques enumerados aquí: Elimine registros duplicados de una tabla SQL sin una clave principal