【问题标题】:sql query to get deleted recordssql查询获取已删除记录
【发布时间】:2012-06-19 14:21:38
【问题描述】:

您有一个表table1,其中包含id 列,即int(11), not null, auto_increment,从1 开始。

假设您有 10,000 条记录。很明显,最后一条记录的 id 是 10,000。 删除 3 条记录后,表中有 9,997 条记录,但最后一条记录 id 值仍为 10,000(如果最后一条记录未删除)。

如何显示使用 1 条 sql 查询删除了哪些记录?

谢谢。

【问题讨论】:

  • 创建一个包含 10,000 个连续值的表作为查找表。然后从查找中选择目标表中不存在的所有记录。 (这总是比尝试动态生成丢失的 ID 更快。)
  • 如果你的 DMBS 有类似 generate_series() 的函数(我不认为 mysql 有),你可以使用它,基于 {min,max},而不是硬连线压延 table .
  • +1 因为我通过回答它学到了一些新东西 :) 一个不错的问题 :)

标签: mysql sql select gaps-and-islands


【解决方案1】:

我认为最简单的方法是创建一个只有 id 的虚拟/临时表。 1-1000 然后左连接到该表。

但请务必在完成后从您的虚拟/临时表中删除“已删除”记录。否则,它们每次都会出现。

>> 编辑 您可以自行加入以确定您是否缺少 ids....

select a.id + 1 MissingIds
from <table> a
left join <table> b
  on a.id = b.id - 1
where b.id is null
  and a.id < 10000

【讨论】:

  • 您真正需要的只是一个数字表或动态生成数字的方法
  • @AndriusNaruševičius 不同意。有时,有一种失败证明方法是专业的,而不是过于复杂的方法。
  • @AndriusNaruševičius 到底有什么不专业的?是不是太快太容易了,所以你不能向你的客户收费很多小时???
  • 无意粗鲁。请定义“专业”。每个解决方案对于每种情况都是独一无二的。不是说这是最好的解决方案,而是因为它不“专业”而将其驳回是不对的。忽略它,因为有更好的可扩展/可管理的解决方案......现在我们正在做饭!
  • @samyi 改进它的一种方法可能是创建一个带有“check_deleted_timestamp”列的真实表,并在检查删除时更新这些记录 - 或在删除原始记录时使用触发器“deleted_timestamp”跨度>
【解决方案2】:

【讨论】:

    【解决方案3】:

    我使用this answer 作为参考。

    您可以使用以下查询来查找间隙,这实质上将为您提供已删除的记录“范围”。例如,在下面的示例中,您在最终结果中返回 2 行,其值为 2 和 3,以及 6 和 7。因此您知道 ID 为 2 到 3 的行已被删除,并且 ID 为已删除 6 到 7 行(总共删除 4 行)。

    我相信这满足了您在“1 SQL 查询”中获得最终结果的要求,而且不使用中间表或虚拟表。

    delimiter $$
    use test
    $$
    
    create table mytable (id int not null auto_increment, name varchar(100), primary key (id));
    $$
    
    insert into mytable (name) values('a')$$
    insert into mytable (name) values('b')$$
    insert into mytable (name) values('c')$$
    insert into mytable (name) values('d')$$
    insert into mytable (name) values('e')$$
    insert into mytable (name) values('f')$$
    insert into mytable (name) values('g')$$
    insert into mytable (name) values('h')$$
    
    
    delete from mytable where id = 2$$
    delete from mytable where id = 3$$
    delete from mytable where id = 6$$
    delete from mytable where id = 7$$
    
    
    SELECT (t1.id + 1) as gap_starts_at
         , (SELECT MIN(t3.id) -1
              FROM mytable t3 
             WHERE t3.id > t1.id) as gap_ends_at
      FROM mytable t1
     WHERE NOT EXISTS (SELECT t2.id FROM mytable t2 WHERE t2.id = t1.id + 1)
    HAVING gap_ends_at IS NOT NULL
    

    输出:

    gap_starts_at  gap_ends_at
    2              3
    6              7
    

    【讨论】:

      【解决方案4】:
      DECLARE @myTestTable1 TABLE
      (
      id INT IDENTITY(1,1) NOT NULL
      ,testVal int
      )
      
      DECLARE @increment AS int = 1
      
      WHILE (@increment <= 10000)
      BEGIN
      INSERT INTO @myTestTable1
      VALUES (@increment)
      
      SET @increment += 1
       END
      
      DELETE FROM @myTestTable1 WHERE id IN (100,200,300)
      
      --SELECT * FROM @myTestTable1
      
       ;WITH Missing (missnum, maxid)
       AS
       (
        SELECT 1 AS missnum, (select max(id) from @myTestTable1)
        UNION ALL
         SELECT missnum + 1, maxid FROM Missing
         WHERE missnum < maxid
         )
           SELECT missnum
           FROM Missing
           LEFT OUTER JOIN @myTestTable1 tt on tt.id = Missing.missnum
           WHERE tt.id is NULL
           OPTION (MAXRECURSION 0); 
      

      但这需要很多时间。我们必须减少时间。

      【讨论】:

        【解决方案5】:

        首先,我将展示生成 10.000 条记录的最简单方法。没有巨大的查询,没有变量。执行时间:~3ms。 LINK

        现在关于我承诺的那个触发器。 LINK

        如您所见,创建一个非常容易。请记住,触发器不仅不需要各种连接更好,而且您还可以存储日期、用户 ID 等(非常可扩展的示例)。 触发器连接的要点是:您不在乎有多少记录/现在/将有多少。您不需要严格控制大小。这就是为什么我称​​sam yi的回答不够专业。抱歉造成误会,我敢肯定我们都不想侮辱任何人。

        通过创建这个示例,我确实学到了一些东西。希望你也这样做了:)

        【讨论】:

        • sqlfiddle.com/#!2/ab17a/1 - 我已经为架构面板下方的“分隔符”命令(注意“|”)构建了一个 UI 替代方案。使用它,您可以构建基于触发器的选项。
        猜你喜欢
        • 1970-01-01
        • 2016-11-30
        • 1970-01-01
        • 1970-01-01
        • 2014-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-02
        相关资源
        最近更新 更多