如何有效地生成更多的彩票号码

时间:2011-12-16 01:30:12

标签: tsql

我是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

2 个答案:

答案 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