SQL中使用NEWID()随机打乱行并保存至新表失效,求解决方案
这个问题我之前帮同事排查过,核心原因得先搞懂:关系型数据库的表本质上是无序的——除非你在查询语句里明确指定ORDER BY,否则数据库根本不保证数据的存储顺序或者返回顺序。
你原来写的select Name into TestTable from Customers order by NEWID(),看起来是让查询结果随机排序后插入,但实际上数据库在执行SELECT INTO时,大多会忽略这个ORDER BY(比如SQL Server就是这样),因为新创建的TestTable没有任何能“记住”插入顺序的结构,数据库会按照它认为最高效的方式去存储数据,所以最终表的顺序和原表一致就不奇怪了。
下面给你两种解决思路,看你需求来选:
思路1:查询时再做随机排序(最推荐)
如果你只是需要每次查TestTable时得到随机顺序的数据,完全不需要在插入阶段折腾,直接在查询时加ORDER BY NEWID()就行:
SELECT * FROM TestTable ORDER BY NEWID();
这样每次执行查询,返回的顺序都是随机的,而且操作最简单,也符合数据库的设计逻辑。
思路2:固化随机顺序到新表(如果必须存储顺序)
如果你确实需要把随机顺序永久存在新表里(比如要给每条记录分配一个随机的序号),可以给新表加一个自增列,利用自增列的特性来保留插入时的随机顺序:
-- 1. 先创建带自增列的TestTable CREATE TABLE TestTable ( RandomOrderId INT IDENTITY(1,1) PRIMARY KEY, Name VARCHAR(50) ); -- 2. 按随机顺序插入数据,自增列会跟着插入顺序生成 INSERT INTO TestTable (Name) SELECT Name FROM Customers ORDER BY NEWID(); -- 3. 查看时按自增列排序,就能得到插入时的随机顺序 SELECT * FROM TestTable ORDER BY RandomOrderId;
这里的RandomOrderId是自增主键,插入时会严格按照SELECT语句返回的随机顺序生成,之后只要按这个列排序,就能固定得到当时的随机结果。
另外要注意:不同数据库的随机函数不一样,你用的NEWID()是SQL Server的写法,如果是MySQL要换成RAND(),Oracle用DBMS_RANDOM.VALUE(),但核心逻辑是一致的。
内容的提问来源于stack exchange,提问作者Ruba Sbeih

