none
SQL如何以给定概率随机删除一些记录? RRS feed

  • 问题

  • 现在有一个表,里面有若干记录。我希望以1/3的概率随机删除一部分记录。注意,不是“随机删除1/3的记录”,而是“对每条记录,有1/3的概率将其删除”,因此实际删除的记录数也应当是随机的。一开始写成这样:

    DELETE FROM 表 WHERE BINARY_CHECKSUM(NEWID())%3=0

    结果发现NEWID()只会计算一次,所以结果是要么全删除,要么一个都不删除……

    2018年1月24日 7:02

答案

  • -- 测试表
    SELECT * INTO #t FROM sys.all_columns;
    -- 删除
    DELETE b 
    FROM #t b CROSS APPLY( SELECT ABS(CHECKSUM(NEWID())) % 3 ) D(v)
    WHERE d.v=0
    ;
    -- 删除测试表
    DROP TABLE #t;

    2018年1月24日 8:20
  • -- 测试表
    SELECT * INTO #t FROM sys.all_columns;
    -- 删除
    DELETE b 
    FROM #t b CROSS APPLY( SELECT ABS(CHECKSUM(NEWID())) % 3 ) D(v)
    WHERE d.v=0
    ;
    -- 删除测试表
    DROP TABLE #t;

    更简明易读的写法:

    DELETE 表 FROM 表 CROSS APPLY (SELECT BINARY_CHECKSUM(NEWID())%3 AS 随机数) AS 随机列 WHERE 随机数=0

    意思是对表的每一行生成一个随机数,最终产生一个随机数组成的随机列拼到原表旁边,相当于临时创建了一个视图进行删除


    2018年2月1日 3:53

全部回复

  • 想出了一个比较笨的办法……先定义一个随机数视图

    CREATE VIEW 随机标识
     AS SELECT BINARY_CHECKSUM(NEWID())%3 AS 随机项 FROM 表

    然后通过视图删基表

    DELETE FROM 随机标识 WHERE 随机项=0

    但是感觉好啰嗦啊,有没有更简洁优雅高效的方法呢?

    2018年1月24日 8:04
  • -- 测试表
    SELECT * INTO #t FROM sys.all_columns;
    -- 删除
    DELETE b 
    FROM #t b CROSS APPLY( SELECT ABS(CHECKSUM(NEWID())) % 3 ) D(v)
    WHERE d.v=0
    ;
    -- 删除测试表
    DROP TABLE #t;

    2018年1月24日 8:20
  • 参考

    https://stackoverflow.com/questions/1045138/how-do-i-generate-random-number-for-each-row-in-a-tsql-select

    DELETE FROM 表 WHERE

    ABS(CHECKSUM(NewId())) % 14


    专注于.NET ERP/CRM开发框架,C/S架构,SQL Server + ORM(LLBL Gen Pro) + Infragistics WinForms


    2018年1月25日 0:44
  • 你这种写法只适用于SELECT,对DELETE不适用。在DELETE下只能得到一个随机数。我在一楼已经说过不行了,你没有仔细看吧。
    2018年1月25日 1:01
  • 能不能解释的详细一些呢?我有点看不懂你写的意思,虽然好像确实管用
    2018年1月25日 1:02
  • 简单地说,针对主表的第条记录, CROSS APPLY 对应的子查询会执行一次

    详细的可以看联机帮助关于 CROSS APPLY 语法的说明

    2018年1月25日 2:41
  • -- 测试表
    SELECT * INTO #t FROM sys.all_columns;
    -- 删除
    DELETE b 
    FROM #t b CROSS APPLY( SELECT ABS(CHECKSUM(NEWID())) % 3 ) D(v)
    WHERE d.v=0
    ;
    -- 删除测试表
    DROP TABLE #t;

    更简明易读的写法:

    DELETE 表 FROM 表 CROSS APPLY (SELECT BINARY_CHECKSUM(NEWID())%3 AS 随机数) AS 随机列 WHERE 随机数=0

    意思是对表的每一行生成一个随机数,最终产生一个随机数组成的随机列拼到原表旁边,相当于临时创建了一个视图进行删除


    2018年2月1日 3:53