删除重复的行

时间:2019-07-03 12:15:53

标签: sqlite

我正在学习SQLite,并构建了一条行,我认为这会删除公仔,但会删除所有行。

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

我希望这能删除重复的行(保留一个)。我知道我可以简单地用不同的行创建一个新表,但是为什么我所做的没有用?谢谢

4 个答案:

答案 0 :(得分:2)

如果timestamp是表中的一列,而这是您要比较的,以便删除重复项,请执行以下操作:

delete from tablename 
where exists (
  select 1 from tablename t
  where t.rowid < tablename.rowid and t.timestamp = tablename.timestamp
)

答案 1 :(得分:2)

在最新版本的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 :(得分:1)

  

为什么我没有做的事?

考虑WHERE条件:

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 )

首先请注意,这是将rowidmax(t.rowid)(从同一列派生的值)进行比较。

由于t.timestamp上的子查询组,聚合函数max()将为每个具有相同t.rowid值的行集分别返回最大/最后t.timestamp。结果列表将排除小于最大值的t.rowid个值。因此,NOT IN操作将找不到那些较小的值,并且将返回true,因此将其删除。

它也使用基本的SQL(没有窗口功能... OVER关键字)。它可能比引用子查询中外部查询的替代方法更有效率,因为该语句只能执行一次子查询,然后使用有效索引来匹配各个记录……无需为每行重新运行查询。为此,它还应该比开窗函数更有效,因为窗口分区本质上是对分区列进行“分组”,但随后必须为每一行执行开窗函数,这是基本聚合查询中不存在的额外步骤。效率并不总是很关键,但需要考虑的重要因素。


顺便说一句,distinct关键字不是函数,不需要/不接受括号。这是一条指令,适用于整个select语句。子查询被解释为

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;

该查询保留了唯一的分组,但每个时间戳仅提供一个行标识符作为“句柄”,以包含/排除删除。

答案 3 :(得分:0)

尝试

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

您可以执行多次