我是SQL的初学者,我正在寻找更多SQL经验,因此我决定设计一个程序来生成X量的随机乐透选择。我所在区域的彩票允许您从1-47中选择5个数字,从1-27中选择1个“超级”数字。诀窍是“兆”号可以重复前面的5个数字,即1,2,3,4,5,兆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
答案 0 :(得分:4)
我在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 )
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;
10000行0秒
100000行1秒
1000000行14秒
10000000行03分29秒
我还应该提到我使用
的原因(ABS(CHECKSUM(NewId())) % 47 + 1)
是每行返回一个随机数。
的解决方案CAST(((47+ 1) - 0) * RAND() + 1 AS TINYINT)
如果你一次选择它们,为每一行返回相同的随机数。要测试此运行此示例:
;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
确定。所以我确实看到了你的评论,我也有解决方案。如果你真的想订购这些数字。算法的复杂性提高,这也意味着算法的时间增加。但我仍然认为这是可行的。但不是以同样的方式。
--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 )
但我仍然设法在一段时间内完成
10000行:0秒
100000行:4秒
1000000行:43秒
10000000行:7分9秒
我希望这个帮助
答案 1 :(得分:0)
我出于好奇而写了这个剧本。它应该比你的脚本做得更好,但我无法确定。
请注意我使用声明的表,如果使用实际表,则在生成更多行时应该更好。
我在大约13秒内生成10000行,大约需要3.5小时才能生成10 000 000行。还远比你描述的Java案例差。
set nocount on
go
declare @i int = 1
declare @t table(nr1 int, nr2 int, nr3 int, nr4 int, nr5 int, mega int, seq int)
while @i <= 10000
begin
;with numbers(nr)
as
(
select 1
union all
select nr+1
from numbers
where nr < 47
)
,mega(nr)
as
(
select 1
union all
select nr+1
from mega
where nr < 27
)
,selectednumbers(nr)
as
(
select top 5 nr
from numbers
order by newid()
)
,selectedmega(mega)
as
(
select top 1 nr
from mega
order by newid()
)
,tmp
as
(
select *
,row_number() over(order by nr) as rownr
from selectednumbers
)
insert into @t
select max(nr1) as nr1
,max(nr2) as nr2
,max(nr3) as nr3
,max(nr4) as nr4
,max(nr5) as nr5
,(select mega from selectedmega) as mega
,@i as seq
from (
select case when rownr = 1 then nr else 0 end as nr1
,case when rownr = 2 then nr else 0 end as nr2
,case when rownr = 3 then nr else 0 end as nr3
,case when rownr = 4 then nr else 0 end as nr4
,case when rownr = 5 then nr else 0 end as nr5
from tmp
) x
set @i = @i + 1
end
select * from @t