如何随机更新行?

时间:2010-03-04 15:37:31

标签: sql sql-server-2008

我想通过表格随机删除一些数据。我正在做一些数据随机化,将真实的名字变成假的等等。其中一个表有一个列,大约40%的时间是空的。我的名字随机发生器应用程序可以在它分配新的名字时在其中的某处投掷硬币。但我最好只是在最后做:随机修剪一些数据。

我有这个代码,但这不起作用,但确实看起来应该对我来说:

Use MyDb
go 

CREATE VIEW vRandNumber 
AS 
SELECT RAND() as RandNumber 

go  

CREATE FUNCTION RandNumber() 
RETURNS float 
AS 
  BEGIN 
  RETURN (SELECT RandNumber FROM vRandNumber) 
  END 

go  

select dbo.RandNumber()

update names set nickname = null 
where ((select dbo.RandNumber()) > 0.5)

当我运行RandNumber函数时,它很好,很随机。但是当我进行更新时,它会在一半时间内更新所有行,而在另一半时间内不会更新所有行。

我想让它在每次运行脚本时更新随机行数。我真的以为像RandNumber这样的函数会为表中的每一行运行一次。显然不是。

如果没有循环且没有控制台应用程序,这可能吗?

编辑:我也尝试了RAND()的几种变体直接在哪里得到了相同的结果。

7 个答案:

答案 0 :(得分:26)

假设您的Names表有一个名为Id的主键字段,这将使随机50%的行中的昵称无效:

update dbo.Names set Nickname = null where Id in
(
    select top 50 percent id from dbo.Names order by NEWID()
)

答案 1 :(得分:1)

RandNumber是一个功能。除非基础数据库数据已更改,否则SQL中的函数必须每次为同一输入输出相同的结果。这是函数的数学定义(与普通编程语言如何处理“函数”相反,后者更像是一个类似函数的构造)。

由于函数的结果在更新语句(这是一个原子操作)期间永远不会改变,因此查询的查询计划编译器只调用RandNumber一次,然后缓存结果。

您可以直接在查询中引用RAND,但如果仍然无效,则必须在存储过程中迭代执行此操作。

答案 2 :(得分:1)

尝试这样的事情:

WHERE DATEPART(ms,CreateDate)>500

其中“CreateDate”是表中已有的实际日期和时间的列。毫秒应该是相当随机的

修改 这是另一种方法:

DECLARE @YourTable table (RowID int, RowValue varchar(5))
INSERT INTO @YourTable VALUES (1,'one')
INSERT INTO @YourTable VALUES (2,'two')
INSERT INTO @YourTable VALUES (3,'three')

SELECT 
    RAND(row_number() over(order by RowID)+DATEPART(ms,GETDATE())),* 
    FROM @YourTable

OUTPUT运行1:

                       RowID       RowValue
---------------------- ----------- --------
0.716200609189072      1           one
0.71621924216033       2           two
0.716237875131588      3           three

(3行受影响)

OUTPUT run 2:

                       RowID       RowValue
---------------------- ----------- --------
0.727007732518828      1           one
0.727026365490086      2           two
0.727044998461344      3           three

(3 row(s) affected)

答案 3 :(得分:1)

RAND()会在查询中保留。

SELECT  RAND()
FROM    names

会给你一组相同的数字。

你需要做这样的事情:

WITH    q AS
        (
        SELECT  *,
                ABS(CHECKSUM(NEWID())) % 2 AS r
        FROM    names
        )
UPDATE  q
SET     nickname = NULL
WHERE   r = 0

答案 4 :(得分:1)

这是正常的分发(非随机)解决方案。它根据Vehicle.ID % 10 + 1 = branch_number

将车辆分配给分支机构
; WITH mytbl AS (
    SELECT TOP 10 *, ROW_NUMBER() OVER (ORDER BY NEWID()) num
    FROM Branch
    ORDER BY num
)

UPDATE v
SET BranchID = mytbl.ID
FROM Vehicle v
    INNER JOIN mytbl ON mytbl.num = v.ID % 10 + 1

SELECT BranchID, COUNT(*) FROM Vehicle GROUP BY BranchID

答案 5 :(得分:0)

怎么样

update names set nickname = null
where  abs(checksum(nickname) % 2) = 0

答案 6 :(得分:0)

每个语句评估一次RAND()(和GetDate / CURRENT_TIMESTAMP)。你需要在某种程度上解决这个问题。一种方法是(如果你有一个方便的行值整数,例如一个ID列),就是调用RAND(ID)。