Удаление повторяющихся строк - PullRequest
0 голосов
/ 03 июля 2019

Я изучаю SQLite и построил линию, которая, как я думал, удалит дубликаты, но вместо этого удалит все строки.

DELETE from tablename WHERE rowid not in (SELECT distinct(timestamp) from tablename);

Я ожидал, что это удалит строки с дубликатом (оставляя один).Я знаю, что могу просто создать новую таблицу с отдельными строками, но почему то, что я сделал, не работает?Спасибо

Ответы [ 4 ]

2 голосов
/ 03 июля 2019

В последних версиях sqlite альтернативой может быть следующее:

DELETE FROM tablename
WHERE rowid IN (SELECT rowid
                FROM (SELECT rowid, row_number() OVER (PARTITION BY timestamp) AS rownum
                      FROM tablename)
                WHERE rownum >= 2);
2 голосов
/ 03 июля 2019

Если timestamp является столбцом в таблице, и это то, что вы хотите сравнить, чтобы удалить дубликаты, то сделайте следующее:

delete from tablename 
where exists (
  select 1 from tablename t
  where t.rowid < tablename.rowid and t.timestamp = tablename.timestamp
)
1 голос
/ 03 июля 2019

почему то, что я сделал, не работает?

Рассмотрим условие ГДЕ:

rowid not in (SELECT distinct(timestamp) from tablename)

Простой ответ заключается в том, что вы не сравниваете данные в одних и тех же столбцах, и при этом они не являются столбцами с данными одного типа. rowid - это автоматически увеличиваемый столбец целых чисел, и я предполагаю, что столбец timestamp является числовым или строковым столбцом, содержащим значения времени, или, возможно, сгенерированные пользователем последовательные числовые значения. Поскольку rowid вероятно никогда не соответствует значению timestamp, операция NOT IN будет всегда возвращать true . Таким образом, каждая строка таблицы будет удалена.

SQL довольно явный, поэтому нет никаких скрытых / таинственных сравнений столбцов. Он не будет автоматически сравнивать значения строк из одного запроса с другим. Обратите внимание, что различные альтернативные операторы делают что-то, чтобы различать строки с дублирующимися значениями ключа (timestamp в вашем случае), либо путем прямого сравнения основного запроса и подзапроса, либо с помощью оконных функций для уникальной маркировки строк с дубликатом значения и т. д.

Просто для удовольствия, вот еще одна альтернатива, которая использует NOT IN как ваш оригинальный код.

DELETE FROM tablename 
WHERE rowid NOT IN (
  SELECT max(t.rowid) FROM tablename t
  GROUP BY t.timestamp )

Сначала обратите внимание, что это сравнение rowid с max(t.rowid), значениями, которые получены из того же столбца.

Поскольку подзапрос группируется по t.timestamp, агрегатная функция max() будет возвращать наибольшее / последнее t.rowid отдельно для каждого набора строк с одинаковым значением t.timestamp. Результирующий список исключит t.rowid значений, которые меньше максимального. Таким образом, операция NOT IN не найдет эти меньшие значения и вернет true, поэтому они будут удалены.

Он также использует базовый SQL (без оконных функций ... ключевое слово OVER). Вероятно, будет более эффективным , чем альтернатива, которая ссылается на внешний запрос из подзапроса, потому что этот оператор может выполнить подзапрос только один раз, а затем использовать эффективный индекс для сопоставления отдельных записей ... он не необходимо повторно выполнить запрос для каждой строки. В этом отношении она также должна быть более эффективной, чем оконная функция, потому что оконное разбиение по существу «группируется» в разделенных столбцах, но затем должно выполнять оконную функцию для каждой строки, что является дополнительным шагом, отсутствующим в базовом агрегированном запросе. Эффективность не всегда важна, но важно учитывать.


Кстати, отличное ключевое слово не является функцией и не требует / принимает круглые скобки. Это директива, которая применяется ко всему оператору выбора. Подзапрос интерпретируется как

SELECT DISTINCT (timestamp) FROM tablename

где DISTINCT интерпретируется изолированно, а скобки интерпретируются как отдельное выражение.


Обновление

Эти два запроса вернут одинаковые данные:

SELECT DISTINCT timestamp FROM tablename;
SELECT timestamp FROM tablename GROUP BY timestamp;

Оба результата удаляют повторяющиеся строки из выходных данных, показывая только уникальные / отличные значения, но ни один из них не имеет «дескриптора» (другой столбец данных), который указывает, какие строки следует сохранить и какие строки удалить. Другими словами, эти запросы возвращают разные значения, но результаты теряют все связи с исходными строками и поэтому не имеют смысла указывать, какие исходные строки следует удалить (или сохранить). Чтобы лучше понять, вам следует запускать подзапросы отдельно, чтобы проверить, что они возвращают, чтобы вы могли понять и проверить, с какими данными вы работаете.

Чтобы сделать эти запросы полезными, нам нужно сделать что-то, чтобы различать строки с дублирующимися значениями ключа . Строки нуждаются в «дескрипторе» - другом значении ключа, которое нужно выбрать для удаления или сохранения этих строк. Попробуйте это ...

SELECT DISTINCT rowid, timestamp FROM tablename;

Но это не сработает, потому что оно применяет ключевое слово DISTINCT ко ВСЕМ возвращаемым столбцам, но так как rowid уже уникален, он обязательно будет выводить каждую строку отдельно, поэтому в запросе нет смысла.

SELECT max(rowid), timestamp FROM tablename GROUP BY timestamp;

Этот запрос сохраняет уникальную группировку, но предоставляет только один rowid на отметку времени в качестве «дескриптора» для включения / исключения для удаления.

0 голосов
/ 05 июля 2019

попробуйте это

DELETE liens from liens where 
id in 
( SELECT * FROM (SELECT min(id) FROM liens group by lkey having count(*) > 1 ) AS c)

Вы можете сделать это много раз

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...