SQL - 在X个表中平均分配相同的值

时间:2015-02-17 16:26:02

标签: sql sql-server-2012 equals

我想知道是否有人知道如何在" x"中平均分配多个相似的值。临时表的数量确保'喜欢'值(此示例中的相同团队名称)永远不会集中到一个特定的表中。我要做的是为比赛创造热量,并在桌子之间平均分配球队。例如:

**Teams**
-----------
Los Angeles
New York
New York
Los Angeles
Florida
Florida
Arizona
Texas
Alabama
Alaska
New York
New York
New York

我希望这样的发行最终可以让所有多个团队在2(或3或4)次加热中均匀分布:

**Heat One**  
-------------                        
Los Angeles                       
New York                          
Florida                           
Arizona                           
Alabama                           
New York                          
New York

**Heat Two**
------------
Los Angeles
New York
Florida
Texas
Alaska
New York

2 个答案:

答案 0 :(得分:5)

从SQL Server 2005开始,存在用于分段数据的本机功能。 NTILE()

NTILE函数是SQL Server 2005中引入的四个窗口函数中的第四个.NTILE采用不同的方法来分区数据。 ROW_NUMBER,RANK和DENSE_RANK将根据分区键生成可变大小的数据桶。 NTILE尝试将数据拆分为相同的固定大小的存储区。 BOL有一个综合页面,比较排名函数if 你想要一个关于它们效果的快速视觉参考。

语法

NTILE的语法与其他窗口函数略有不同。它是NTILE(@BUCKET_COUNT) OVER ([PARTITION BY _] ORDER BY _),其中@BUCKET_COUNT是正整数或bigint值。

挑战在于确保我们获得良好的分布,并且该部分受随机数生成器的迷惑(newid calls /(SELECT NULL))。

利用Rhys的设置

CREATE table dbo.Teams (TeamId int, TeamName varchar(32));

insert dbo.Teams values
( 1, 'Los Angeles'),
( 2, 'New York'),
( 3, 'New York'),
( 4, 'Los Angeles'),
( 5, 'Florida'),
( 6, 'Florida'),
( 7, 'Arizona'),
( 8, 'Texas'),
( 9, 'Alabama'),
(10, 'Alaska'),
(11, 'New York'),
(12, 'New York'),
(13, 'New York');

SELECT
    NTILE(2) OVER (ORDER BY NEWID()) AS Heat
,   NTILE(2) OVER (ORDER BY (SELECT NULL)) AS HeatAlternate
,   T.TeamName
,   T.TeamId
FROM
    dbo.Teams AS T
ORDER BY
    1,3;

这种方法的一个好处是它可以通过简单地改变传递给ntile的值来切换出你想要的任何大小。它也应该更好地扩展,因为它只需要通过源表一次。

答案 1 :(得分:0)

这种方法听起来不对(有单独的表名为Heat1,Heat2等),所以你可能想重新思考你在做什么,但如果你的情况决定这是一个很好的方法那么如何分配随机每个团队的唯一(但顺序)数字然后使用MOD来分散团队的热量?为了让“喜欢”的队伍(同一队名)变成不同的热量,他们只需要随机组合在一起,MOD就会将它们分开。

create table dbo.Teams (TeamId int, TeamName varchar(32))
go

insert dbo.Teams values
( 1, 'Los Angeles'),
( 2, 'New York'),
( 3, 'New York'),
( 4, 'Los Angeles'),
( 5, 'Florida'),
( 6, 'Florida'),
( 7, 'Arizona'),
( 8, 'Texas'),
( 9, 'Alabama'),
(10, 'Alaska'),
(11, 'New York'),
(12, 'New York'),
(13, 'New York')
go

-- First get a random number per unique team name
; with cte as (
    select row_number() over (order by newid()) as lrn, t.TeamName
    from dbo.Teams t
    group by t.TeamName     
)
-- Second get a unique random number per team with like teams ordered together
select row_number() over (order by lrn, newid()) - 1 as rn, t.*
into #teams
from dbo.Teams t
    join cte c on c.TeamName = t.TeamName

select 'Heat1', * 
from #teams 
where rn % 4 = 0

select 'Heat2', * 
from #teams 
where rn % 4 = 1

select 'Heat3', * 
from #teams 
where rn % 4 = 2

select 'Heat4', * 
from #teams 
where rn % 4 = 3