我是 SQL 的初学者,我一直在寻找更多的 SQL 经验,因此我决定设计一个过程来生成 X 数量的随机乐透选择。我所在地区的彩票允许您从 1-47 中选择 5 个号码,以及从 1-27 中选择 1 个“超级”号码。诀窍是“mega”数字可以与之前的 5 个数字重复,即 1、2、3、4、5、mega 1。
我创建了以下过程来生成 1000 万个彩票选秀权,该过程花了 12 小时 57 分钟才能完成。而我的朋友用 java 测试了同样的事情,只花了几秒钟。我想知道我是否可以对代码进行任何改进,或者我是否犯了任何错误?我对此很陌生,因此我正在努力学习更好的方法等,欢迎所有评论。
USE lotto
DECLARE
@counter INT,
@counter1 INT,
@pm SMALLINT,
@i1 SMALLINT,
@i2 SMALLINT,
@i3 SMALLINT,
@i4 SMALLINT,
@i5 SMALLINT,
@sort int
SET @counter1=0
TRUNCATE TABLE picks
WHILE @counter1<10000000
BEGIN
TRUNCATE TABLE sort
SET @counter = 1
WHILE @counter < 6
BEGIN
INSERT INTO sort (pick)
SELECT CAST(((47+ 1) - 0) * RAND() + 1 AS TINYINT)
IF (SELECT count(distinct pick) FROM sort)<@counter
BEGIN
TRUNCATE TABLE sort
SET @counter=1
END
ELSE IF (SELECT COUNT(DISTINCT pick) FROM sort)=@counter
BEGIN
SET @counter = @counter + 1
END
END
SET @sort = 0
WHILE @sort<5
BEGIN
UPDATE sort
SET sort=@sort
WHERE pick = (SELECT min(pick) FROM sort WHERE sort is null)
SET @sort=@sort + 1
END
SET @i1 = (SELECT pick FROM sort WHERE sort = 0)
SET @i2 = (SELECT pick FROM sort WHERE sort = 1)
SET @i3 = (SELECT pick FROM sort WHERE sort = 2)
SET @i4 = (SELECT pick FROM sort WHERE sort = 3)
SET @i5 = (SELECT pick FROM sort WHERE sort = 4)
SET @pm = (CAST(((27+ 1) - 0) * RAND() + 1 AS TINYINT))
INSERT INTO picks(
First,
Second,
Third,
Fourth,
Fifth,
Mega,
Sequence
)
Values(
@i1,
@i2,
@i3,
@i4,
@i5,
@pm,
@counter1
)
SET @counter1 = @counter1+1
END
Run Code Online (Sandbox Code Playgroud)
我在 0 秒内生成了 10000 行。我用另一种方式做到了。希望对你有帮助
;WITH Nbrs ( n ) AS (
SELECT 1 UNION ALL
SELECT 1 + n FROM Nbrs WHERE n < 10000 )
SELECT
(ABS(CHECKSUM(NewId())) % 47 + 1) AS First,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Second,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Third,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Fourth,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Fifth,
(ABS(CHECKSUM(NewId())) % 27 + 1) AS Mega,
Nbrs.n AS Sequence
FROM
Nbrs
OPTION ( MAXRECURSION 0 )
Run Code Online (Sandbox Code Playgroud)
10000 行 0 秒
100000 行 1 秒
1000000 行 13 秒
10000000 行 02 分 21 秒
或者使用交叉连接
WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
E02(N) AS (SELECT 1 FROM E00 a, E00 b),
E04(N) AS (SELECT 1 FROM E02 a, E02 b),
E08(N) AS (SELECT 1 FROM E04 a, E04 b),
E16(N) AS (SELECT 1 FROM E08 a, E08 b),
E32(N) AS (SELECT 1 FROM E16 a, E16 b),
Nbrs(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32)
SELECT
(ABS(CHECKSUM(NewId())) % 47 + 1) AS First,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Second,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Third,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Fourth,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Fifth,
(ABS(CHECKSUM(NewId())) % 27 + 1) AS Mega,
Nbrs.n AS Sequence
FROM Nbrs
WHERE N <= 10000000;
Run Code Online (Sandbox Code Playgroud)
10000 行 0 秒
100000 行 1 秒
1000000 行 14 秒
10000000 行 03 分 29 秒
我还应该提到我使用的原因
(ABS(CHECKSUM(NewId())) % 47 + 1)
Run Code Online (Sandbox Code Playgroud)
是它每行返回一个随机数。解决方案与
CAST(((47+ 1) - 0) * RAND() + 1 AS TINYINT)
Run Code Online (Sandbox Code Playgroud)
如果一次性选择它们,则为每一行返回相同的随机数。要测试此运行此示例:
;WITH Nbrs ( n ) AS (
SELECT 1 UNION ALL
SELECT 1 + n FROM Nbrs WHERE n < 5 )
SELECT
CAST(((47+ 1) - 0) * RAND() + 1 AS TINYINT) AS Random,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS RadomCheckSum,
Nbrs.n AS Sequence
FROM Nbrs
Run Code Online (Sandbox Code Playgroud)
好的。所以我确实看到了你的评论,我也有一个解决方案。如果你真的想订购数字。算法的复杂度增加,这也意味着算法的时间增加。但我仍然认为这是可行的。但不是以同样简洁的方式。
--Yeah declaring a temp table for just the random order number
DECLARE @tbl TABLE(value int)
--The same function but with the number of the random numbers
;WITH Nbrs ( n ) AS (
SELECT 1 UNION ALL
SELECT 1 + n FROM Nbrs WHERE n < 5 )
INSERT INTO @tbl
(
value
)
SELECT
Nbrs.n AS Sequence
FROM Nbrs
;WITH Nbrs ( n ) AS (
SELECT CAST(1 as BIGINT) UNION ALL
SELECT 1 + n FROM Nbrs WHERE n < 100000 )
SELECT
tblOrderRandomNumbers.[1] AS First,
tblOrderRandomNumbers.[2] AS Second,
tblOrderRandomNumbers.[3] AS Third,
tblOrderRandomNumbers.[4] AS Fourth,
tblOrderRandomNumbers.[5] AS Fifth,
(ABS(CHECKSUM(NewId())) % 27 + 1) AS Mega,
Nbrs.n AS Sequence
FROM
Nbrs
--This cross join. Joins with the declared table
CROSS JOIN
(
SELECT
[1], [2], [3], [4], [5]
FROM
(
SELECT
Random,
ROW_NUMBER() OVER(ORDER BY tblRandom.Random ASC) AS RowNumber
FROM
(
SELECT
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Random
FROM
@tbl AS tblNumbers
) AS tblRandom
)AS tblSortedRadom
--A pivot makes the rows to columns. Using the row index over order of the random number
PIVOT
(
AVG(Random)
FOR RowNumber IN ([1], [2], [3], [4],[5])
) as pivottable
) AS tblOrderRandomNumbers
OPTION ( MAXRECURSION 0 )
Run Code Online (Sandbox Code Playgroud)
但我仍然设法在短时间内完成
10000 行:0 秒
100000 行:4 秒
1000000 行:43 秒
10000000 行:7 分 9 秒
我希望这有帮助