如何将随机值插入 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 数据库插入值
如何在 C# 控制台应用程序中使用 XmlTextReader 将 XML 数据插入 SQL Server 表?