Sql 如何随机更新行?

Sql 如何随机更新行?,sql,sql-server-2008,Sql,Sql Server 2008,我想通过一个表格,随机删除一些数据。我正在做一些数据随机化,把真实的名字变成假名字等等。好的,其中一个表有一个列,大约40%的时间是空的。“我的名字随机化器”应用程序可以在指定新名字时在其中的某个位置掷硬币。但我更愿意在最后这样做:随机删减一些数据 我有这样的代码,它不起作用,但在我看来它确实应该: Use MyDb go CREATE VIEW vRandNumber AS SELECT RAND() as RandNumber go CREATE FUNCTION Rand

我想通过一个表格,随机删除一些数据。我正在做一些数据随机化,把真实的名字变成假名字等等。好的,其中一个表有一个列,大约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这样的函数会对表中的每一行运行一次。显然不是

如果没有循环和控制台应用程序,这是可能的吗


编辑:我还在where directly中使用了RAND()的几个变体进行了尝试,得到了相同的结果

RandNumber
是一个函数。SQL中的函数每次必须为相同的输入输出相同的结果,除非基础数据库数据已更改。这是函数的数学定义(与普通编程语言对待“函数”的方式相反,后者更像是一个函数式构造)

由于函数的结果在update语句(原子操作)期间不应更改,因此查询的查询计划编译器只调用
RandNumber
一次,然后缓存结果

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

如何

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

试着这样做:

WHERE DATEPART(ms,CreateDate)>500
WITH    q AS
        (
        SELECT  *,
                ABS(CHECKSUM(NEWID())) % 2 AS r
        FROM    names
        )
UPDATE  q
SET     nickname = NULL
WHERE   r = 0
其中“CreateDate”是表中已存在的列,其中包含实际日期和时间。t毫秒应该是相当随机的

编辑 以下是另一种方法:

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
输出运行1:

                       RowID       RowValue
---------------------- ----------- --------
0.716200609189072      1           one
0.71621924216033       2           two
0.716237875131588      3           three
(3行受影响)

输出运行2:

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

(3 row(s) affected)

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

update dbo.Names set Nickname = null where Id in
(
    select top 50 percent id from dbo.Names order by NEWID()
)
RAND()(和GetDate/CURRENT_TIMESTAMP)对每个语句计算一次。你需要一些方法来解决这个问题。一种方法是(如果您有一个方便的行值整数,例如ID列),则改为调用RAND(ID)。

RAND()
在查询中持续存在

SELECT  RAND()
FROM    names
将给您一组相等的数字

您需要这样做:

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

这是正态分布(非随机)解。它根据
Vehicle.ID%10+1=分支机构编号将车辆分配给分支机构

; 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


您可以使用:
WHERE RAND()>0.5
。不需要视图和函数。@OMG:尝试过,结果相同。10k视图,7次投票;smhOK,但我听说当您在select中的where中执行getdate()时,getdate()将对select中的每一行运行一次。这不正确吗?在MS-SQL中,函数可以是确定性的(如您所述),也可以是非确定性的。请参见RAND函数是非确定性的。在这种情况下,几乎每个函数都将以确定性方式运行,因为
update
是原子的。因此,即使调用了一个通常不确定的函数,它的模式绑定特性也会被以下事实所否定:在查询执行期间,基础数据不能更改。我认为这必须以迭代方式进行,除非您可以强制查询计划编译器将函数视为非确定性函数,尽管它不想这样做。不,我用where运行了更新,每次运行时它都会更新所有行。@jcollumn,奇数/偶数行如何?@jcollumn-好的,我测试了这个,它会起作用的。。。警告空名称或“常量”名称都会做同样的事情,所以它不是完全随机的。实际上,这很好,因为昵称列在其他地方被随机分配,使用C#代码,所以它会更随机。是的,我在你的问题中看到了-@Quassnoi指出,你可以使用newid()获得一个随机字符串和校验和,但是对于您的数据集,这会更快。这虽然有效,但效率低下——为每一行生成一个新的GUID将比为该行生成一个整数花费更长的时间。Pfft,来吧!对于这种用例,超级性能真的是一个问题吗?谈论过早优化。我刚刚在一个有182770行的表上尝试了这种方法,它在11秒钟内就运行了。但它将始终更新相同数量的行。我想我需要一个循环来更新随机数目的行。是的,性能很好,我在25秒内得到了655k行。这不是prod代码中会出现的类型。好的,因此,在某个范围内,提前添加一两行,随机确定要更新的行数,并使用该绝对值而不是“50%”。不。RAND(ID),其中ID每行变化,每行调用一次。这与OPs问题无关。