如何将随机值插入 SQL Server 表?

Posted

技术标签:

【中文标题】如何将随机值插入 SQL Server 表?【英文标题】:How can I insert random values into a SQL Server table? 【发布时间】:2010-11-30 21:20:19 【问题描述】:

我正在尝试将预定义值列表中的值随机插入到表中以进行测试。我尝试使用在这个 *** 问题上找到的解决方案:

***.com/.../update-sql-table-with-random-value-from-other-table

当我尝试这个时,我插入的所有“随机”值对于所有 3000 条记录都是完全相同的。

当我运行实际选择随机行的查询部分时,每次手动运行它都会选择一条随机记录,所以我知道查询有效。我对正在发生的事情的最佳猜测是:

SQL Server 正在以某种方式优化 SELECT,不允许对子查询进行多次评估 随机值的种子在查询更新的每条记录上都是相同的

我被困在我的选择上。我做错了什么,还是有其他方法我应该这样做?

这是我正在使用的代码:

DECLARE @randomStuff TABLE ([id] INT, [val] VARCHAR(100))

INSERT INTO @randomStuff ([id], [val]) 
VALUES ( 1,  'Test Value 1' )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 2,  'Test Value 2' )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 3,  'Test Value 3' )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 4,  'Test Value 4' )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 5,  'Test Value 5' )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 6,  null )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 7,  null )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 8,  null )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 9,  null )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 10, null )

UPDATE MyTable
SET MyColumn = (SELECT TOP 1 [val] FROM @randomStuff ORDER BY NEWID())

【问题讨论】:

这个问题/答案可能有用:***.com/a/9039661/47226 【参考方案1】:

当查询引擎看到这个...

(SELECT TOP 1 [val] FROM @randomStuff ORDER BY NEWID())

...就像,“哦,一个可缓存的标量子查询,我要缓存它!”

您需要欺骗查询引擎,使其认为它是不可缓存的。 jfar 的answer 很接近,但查询引擎足够聪明,可以看到MyTable.MyColumn = MyTable.MyColumn 的重言式,但它不够聪明,无法看穿。

UPDATE MyTable
   SET MyColumn = (SELECT TOP 1 val
                     FROM @randomStuff r
                          INNER JOIN MyTable _MT
                                  ON M.Id = _MT.Id
                    ORDER BY NEWID())
 FROM MyTable M

通过将外部表 (MT) 引入子查询,查询引擎假定需要重新评估子查询。任何事情都可以正常工作,但我选择了 MyTable.Id 的(假定的)主键,因为它会被索引并且只会增加很少的开销。

光标可能同样快,但肯定没有那么有趣。

【讨论】:

好吧,我不记得你是否可以像在 SQL Server 2000 中那样执行 INNER JOIN,但是有一种方法可以解决它,我在 2005 年之前一直使用它。那也是很多年前让我记得,虽然。但这应该在 2005 年和以后正常工作。 +1 这太棒了,但是有一个小错字,ON MT.Id = _MT.Id 应该是ON M.Id = _MT.Id 正如@Rippo 所建议的,完整的查询应该是:UPDATE M SET MyColumn = (SELECT TOP 1 val FROM @randomStuff INNER JOIN MyTable _MT ON M.Id = _MT.Id ORDER BY NEWID()) FROM MyTable M。我还注意到r 没有被使用并改为UPDATE M 而不是UPDATE MyTable。 +1 游标不那么有趣【参考方案2】:

使用交叉连接生成随机数据

【讨论】:

你有我可以使用的例子吗?我不熟悉交叉连接的概念。【参考方案3】:

我玩过这个,发现了一种相当老套的方法,即使用中间表变量。

一旦设置了@randomStuff,我们就会这样做(注意在我的例子中,@MyTable 是一个表格变量,请根据您的普通表格进行相应调整):

DECLARE @randomMappings TABLE (id INT, val VARCHAR(100), sorter UNIQUEIDENTIFIER)

INSERT INTO @randomMappings 
SELECT M.id, val, NEWID() AS sort 
FROM @MyTable AS M 
CROSS JOIN @randomstuff

所以在这一点上,我们有一个中间表,其中包含(mytable id,随机值)的每个组合,以及特定于该组合的每一行的随机排序值。那么

DELETE others FROM @randomMappings AS others 
INNER JOIN @randomMappings AS lower 
ON (lower.id = others.id) AND (lower.sorter < others.sorter)

这是一个老技巧,它删除给定 MyTable.id 的所有行,除了排序值较低的行 - 将值较小的表连接到自身,并删除任何连接成功的地方。这只是留下了最低值。因此,对于每个 MyTable.id,我们只剩下一个(随机)值。然后我们将其重新插入表中:

UPDATE @MyTable
SET MyColumn = random.val
FROM @MyTable m, @randomMappings AS random
WHERE (random.id = m.id)

你就完成了!

这很hacky...

【讨论】:

【参考方案4】:

我现在没有时间检查这个,但我的直觉告诉我,如果你要在服务器上创建一个函数来获取随机值,它不会优化它。

那么你就会有

UPDATE MyTable
Set MyColumn = dbo.RANDOM_VALUE()

【讨论】:

【参考方案5】:

这里没有优化。

您使用选择单个值的子查询,没有什么可优化的。

您还可以尝试将您更新的表中的一列放在选择中,看看是否会改变任何内容。这可能会触发对 MyTable 中每一行的评估

UPDATE MyTable
SET MyColumn = (SELECT TOP 1 [val] FROM @randomStuff ORDER BY NEWID()
    WHERE MyTable.MyColumn = MyTable.MyColumn )

【讨论】:

【参考方案6】:

我想出了一个解决方案,它有点小技巧而且效率很低(更新 3000 条记录需要 10 秒左右)。因为这是用来生成测试数据的,所以我不必担心速度。

在这个解决方案中,我遍历表中的每一行并一次更新一行的值。它似乎有效:

DECLARE @rows INT 
DECLARE @currentRow INT

SELECT @rows = COUNT(*) FROM dbo.MyTable
SET @currentRow = 1

WHILE @currentRow < @rows
BEGIN 

UPDATE MyTable
SET MyColumn = (SELECT TOP 1 [val] FROM @randomStuff ORDER BY NEWID())
WHERE MyPrimaryKey = (SELECT b.MyPrimaryKey
 FROM(SELECT a.MyPrimaryKey, ROW_NUMBER() OVER (ORDER BY MyPrimaryKey) AS rownumber
      FROM MyTable a) AS b
 WHERE @currentRow = b.rownumber
)

SET @currentRow = @currentRow + 1
END 

【讨论】:

以上是关于如何将随机值插入 SQL Server 表?的主要内容,如果未能解决你的问题,请参考以下文章

如何比较两个表的列并将值插入到基于 SQL Server 中存储过程中的比较的新表中

如何从数据表 vb.net 向 sql server 数据库插入值

如何在插入时在 SQL Server 中创建触发器?

如何在 C# 控制台应用程序中使用 XmlTextReader 将 XML 数据插入 SQL Server 表?

C# 后台如何向SQL数据库中插入一定时间范围内的随机日期值,到日就可以!!

SQL Server - 如何将散列密码插入表?