SO Question引出了以下问题。
如果一个表有16行,我想在表中添加一个字段,其中数字1,2,3,4,5,...,16随机排列,即第1行的'RndVal'字段这可能是2,然后对于第2行,它可能是5,即16个整数中的每一个都需要在没有重复的情况下出现。
为什么以下不起作用?理想情况下,我希望看到这个工作,然后看看替代解决方案。
这会创建表格ok:
IF OBJECT_ID('tempdb..#A') IS NOT NULL BEGIN DROP TABLE #A END
IF OBJECT_ID('tempdb..#B') IS NOT NULL BEGIN DROP TABLE #B END
IF OBJECT_ID('tempdb..#C') IS NOT NULL BEGIN DROP TABLE #C END
IF OBJECT_ID('tempdb..#myTable') IS NOT NULL BEGIN DROP TABLE #myTable END
CREATE TABLE #B (B_ID INT)
CREATE TABLE #C (C_ID INT)
INSERT INTO #B(B_ID) VALUES
(10),
(20),
(30),
(40)
INSERT INTO #C(C_ID)VALUES
(1),
(2),
(3),
(4)
CREATE TABLE #A
(
B_ID INT
, C_ID INT
, RndVal INT
)
INSERT INTO #A(B_ID, C_ID, RndVal)
SELECT
#B.B_ID
, #C.C_ID
, 0
FROM #B CROSS JOIN #C;
然后我尝试使用以下内容添加随机列。逻辑是在1到16之间添加随机数>然后有效地覆盖与其他数字重复的任何数字>在一个循环......
SELECT
ROW_NUMBER() OVER(ORDER BY B_ID) AS Row
, B_ID
, C_ID
, RndVal
INTO #myTable
FROM #A
DECLARE @rowsRequired INT = (SELECT COUNT(*) CNT FROM #myTable)
DECLARE @i INT = (SELECT @rowsRequired - SUM(CASE WHEN RndVal > 0 THEN 1 ELSE 0 END) FROM #myTable)--0
DECLARE @end INT = 1
WHILE @end > 0
BEGIN
SELECT @i = @rowsRequired - SUM(CASE WHEN RndVal > 0 THEN 1 ELSE 0 END) FROM #myTable
WHILE @i>0
BEGIN
UPDATE x
SET x.RndVal = FLOOR(RAND()*@rowsRequired)
FROM #myTable x
WHERE x.RndVal = 0
SET @i = @i-1
END
--this is to remove possible duplicates
UPDATE c
SET c.RndVal = 0
FROM
#myTable c
INNER JOIN
(
SELECT RndVal
FROM #myTable
GROUP BY RndVal
HAVING COUNT(RndVal)>1
) t
ON
c.RndVal = t.RndVal
SET @end = @@ROWCOUNT
END
TRUNCATE TABLE #A
INSERT INTO #A
SELECT
B_ID
, C_ID
, RndVal
FROM #myTable
如果原始表有6行,那么结果应该像这样
B_ID|C_ID|RndVal
----------------
| | 5
| | 4
| | 1
| | 6
| | 3
| | 2
答案 0 :(得分:2)
我不明白你的代码,坦率地说
这将使用随机数更新每一行,非重复数字介于1和表格中的行数
UPDATE T
SET SomeCol = T2.X
FROM
MyTable T
JOIN
(
SELECT
KeyCol, ROW_NUMBER() OVER (ORDER BY NEWID()) AS X
FROM
MyTable
) T2 ON T.KeyCol = T2.KeyCol
这更简洁,但无法测试它是否按预期工作
UPDATE T
SET SomeCol = X
FROM
(
SELECT
SomeCol, ROW_NUMBER() OVER (ORDER BY NEWID()) AS X
FROM
MyTable
) T
答案 1 :(得分:1)
当你添加TOP(1)(因为你需要更新第一个RndVal = 0记录)和+1(因为否则你的零标记没有任何意义)你的更新,事情将开始移动。但速度非常慢(在我过时的笔记本电脑上大约40秒)。这是因为,当#myTable被生成的随机数填充时,丢失数字的可能性越来越小 - 你通常会重复,并且必须重新开始。
UPDATE top (1) x
SET x.RndVal = FLOOR(RAND()*@rowsRequired) + 1
FROM #myTable x
WHERE x.RndVal = 0
当然,@ gbn有完全有效的解决方案。
答案 2 :(得分:0)
这与前一个答案基本相同,但具体针对您的代码:
;WITH CTE As
(
SELECT B_ID, C_ID, RndVal,
ROW_NUMBER() OVER(ORDER BY NewID()) As NewOrder
FROM #A
)
UPDATE CTE
SET RndVal = NewOrder
SELECT * FROM #A ORDER BY RndVal