Sql 如何使用另一个表中的随机行更新表中的每一行

Sql 如何使用另一个表中的随机行更新表中的每一行,sql,sql-server,tsql,random,sql-server-2008-r2,Sql,Sql Server,Tsql,Random,Sql Server 2008 R2,我正在构建我的第一个去识别脚本,我的方法遇到了问题 我有一个表dbo.pseudonames,它的firstname列填充了200行数据。此200行列中的每一行都有一个值(无一行为空)。此表还有一个编号为1-200的id列(int,主键,非null) 我想做的是,在一条语句中,用从我的假名表中随机选择的名字数据重新填充整个用户表 要生成用于拾取的随机数,我使用的是ABS(校验和(NewId())%200。每次我选择ABS(Checksum(NewId())%200时,我都会得到一个数值,该数值在

我正在构建我的第一个去识别脚本,我的方法遇到了问题

我有一个表
dbo.pseudonames
,它的
firstname
列填充了200行数据。此200行列中的每一行都有一个值(无一行为空)。此表还有一个编号为1-200的
id
列(int,主键,非null)

我想做的是,在一条语句中,用从我的
假名
表中随机选择的
名字
数据重新填充整个
用户

要生成用于拾取的随机数,我使用的是
ABS(校验和(NewId())%200
。每次我
选择ABS(Checksum(NewId())%200
时,我都会得到一个数值,该数值在我所寻找的范围内,没有间歇性的不稳定行为

但是,当我在以下语句中使用此公式时:

SELECT pn.firstname 
FROM DeIdentificationData.dbo.pseudonyms pn 
WHERE pn.id = ABS(Checksum(NewId())) % 200
我得到的结果是断断续续的。我想说,大约30%的结果返回从表中选择的一个名称(这是预期结果),大约30%返回的结果不止一个(令人困惑的是,没有重复的
id
列值),大约30%返回的结果为NULL(即使
firstname
列中没有空行)

我确实为这个具体问题找了好一阵子,但到目前为止没有结果。我假设这个问题与使用这个公式作为指针有关,但是如果不这样做,我将不知所措


思考?

为什么问题中的查询会返回意外结果

SELECT * FROM @VarUsers;
ID   UserName
1    PseudonymName41
2    PseudonymName132
3    PseudonymName177
...
998  PseudonymName60
999  PseudonymName141
1000 PseudonymName157
原始查询从
笔名中选择。服务器扫描表格的每一行,从该行中选择
ID
,生成一个随机数,将生成的数字与
ID
进行比较

当为特定行生成的编号碰巧与该行的
ID
相同时,该行将在结果集中返回。很有可能生成的编号与
ID
不同,并且生成的编号与
ID
多次重合

更详细一点:

  • 服务器选择ID为1的行
  • 生成一个随机数,例如
    25
    。为什么不呢?一个不错的随机数
  • 是否
    1=25
    ?否=>不返回此行
  • 服务器选择ID为2的行
  • 生成一个随机数,例如
    125
    。为什么不呢?一个不错的随机数
  • 是否
    2=125
    ?否=>不返回此行
  • 等等

样本数据

DECLARE @VarPseudonyms TABLE (ID int IDENTITY(1,1), PseudonymName varchar(50) NOT NULL);
DECLARE @VarUsers TABLE (ID int IDENTITY(1,1), UserName varchar(50) NOT NULL);

INSERT INTO @VarUsers (UserName)
SELECT TOP(1000)
    'UserName' AS UserName
FROM sys.all_objects
ORDER BY sys.all_objects.object_id;

INSERT INTO @VarPseudonyms (PseudonymName)
SELECT TOP(200)
    'PseudonymName'+CAST(ROW_NUMBER() OVER(ORDER BY sys.all_objects.object_id) AS varchar) AS PseudonymName
FROM sys.all_objects
ORDER BY sys.all_objects.object_id;
Users
有1000行,每行具有相同的
UserName
。表
假名
有200行不同的
假名

SELECT * FROM @VarUsers;
ID   UserName
--   --------
1    UserName
2    UserName
...
999  UserName
1000 UserName

SELECT * FROM @VarPseudonyms;
ID   PseudonymName
--   -------------
1    PseudonymName1
2    PseudonymName2
...
199  PseudonymName199
200  PseudonymName200
第一次尝试

起初我尝试了一种直接的方法。对于
用户
中的每一行,我想从
假名中随机获得一行

SELECT
    U.ID
    ,U.UserName
    ,CA.PseudonymName
FROM
    @VarUsers AS U
    CROSS APPLY
    (
        SELECT TOP(1)
            P.PseudonymName
        FROM @VarPseudonyms AS P
        ORDER BY CRYPT_GEN_RANDOM(4)
    ) AS CA
;
结果表明,optimizer太聪明了,这产生了一些随机性,但每个
用户都有相同的
假名
,这不是我所期望的:

ID   UserName   PseudonymName
1    UserName   PseudonymName181
2    UserName   PseudonymName181
...
999  UserName   PseudonymName181
1000 UserName   PseudonymName181
因此,我对这种方法做了一些调整,首先为
用户
中的每一行生成一个随机数。然后,我使用生成的编号,使用
交叉应用
用户
中的每一行查找具有该
ID的
假名

CTE_用户
有一个额外的列,随机数从1到200。在
CTE\u Joined
中,我们从
假名中为每个
用户选择一行。
最后,我们更新原始的
Users

最终解决方案

WITH
CTE_Users
AS
(
    SELECT
        U.ID
        ,U.UserName
        ,1 + 200 * (CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5) AS rnd
    FROM @VarUsers AS U
)
,CTE_Joined
AS
(
    SELECT
        CTE_Users.ID
        ,CTE_Users.UserName
        ,CA.PseudonymName
    FROM
        CTE_Users
        CROSS APPLY
        (
            SELECT P.PseudonymName
            FROM @VarPseudonyms AS P
            WHERE P.ID = CAST(CTE_Users.rnd AS int)
        ) AS CA
)
UPDATE CTE_Joined
SET UserName = PseudonymName;
结果

SELECT * FROM @VarUsers;
ID   UserName
1    PseudonymName41
2    PseudonymName132
3    PseudonymName177
...
998  PseudonymName60
999  PseudonymName141
1000 PseudonymName157

使用适当的软件(MySQL、Oracle、DB2等)和版本(例如,
sql-server-2014
)标记数据库问题很有帮助。语法和特征的差异通常会影响答案。如果您正在使用SQL Server,您可能需要考虑…更新标签,谢谢<代码>ABS(校验和(NewId())
按行重新计算。你可能想要兰德,但事实并非如此。我喜欢crypt\u gen\u random,很好的发现。但是,我不确定如何将随机数的范围限制在1-200之间?Martin我想得到的是,对于我拉取并更新用户表的每一行,都有一个新的随机值。如果没有对每行重新计算公式,是否意味着我将使用相同的值设置每行?