如何将一个表中的行均匀分布到TSQL中另一个表中的行?

时间:2015-03-18 18:17:18

标签: sql-server algorithm tsql join

我试图弄清楚一个SQL查询,它会将记录从一个表分配或分配到另一个表。解释它的最好方法是通过一个人为的例子。

假设我有一张员工表,我想从颜色表中分配每种颜色。

我想确保颜色均匀分布,但员工没有任何属性可以预测他们会收到哪种颜色。

雇员:

Sam
John
Jack
April
Sonny
Jill
Jane

颜色

Red
Green
Blue

结果:

Sam - Red
John - Green
Jack - Blue
April - Red
Sonny - Green
Jill - Blue
Jane - Red

如何在TSQL中构建此连接?

3 个答案:

答案 0 :(得分:2)

我认为你想使用NTILE函数和一个参数,即颜色的数量。像这样:

;WITH Employees AS 
    (SELECT EmployeeName, NTILE(3) OVER (ORDER BY EmployeeName ASC) as ColorNumber FROM (values 
        ('John'),('Jack'),('April'),('Sonny'),('Jill'),('Jane')) as e(EmployeeName)
    ),
    Colors AS 
    (SELECT ColorName, ROW_NUMBER() OVER (ORDER BY ColorName ASC) as ColorNumber FROM (values 
        ('Red'),('Green'),('Blue')) as c(ColorName)
    )
SELECT EmployeeName, ColorName
FROM Employees
INNER JOIN Colors ON Employees.ColorNumber = Colors.ColorNumber

答案 1 :(得分:2)

我知道问题是关于SQLServer的,但对于那些对没有NTILE的解决方案感兴趣并只使用row_number的人来说:

-- (PostgreSQL syntax, but can be easly adapted to any DB)

with 

-- "uses" a dummy colors table just for testing
colors as 
  (select 'Red' as color union all
   select 'Green'        union all
   select 'Blue' 
  )
,

-- "uses" a dummy employees table just for testing
employees as 
  (select 'John' as employee union all
   select 'Jack'             union all
   select 'April'            union all
   select 'Sonny'            union all
   select 'Jill'             union all
   select 'Jane'             
  )
,

-- here's the trick: 

-- first we define a code_num as row_number for each color
c as
(select *, 
        row_number() over() as color_num 
   from colors
),

-- and then we define a code_num for each employee as 
-- ((row_number-1) "mod" (colors' table count)) +1
e as 
(select *, 
        (((row_number() over())-1) % (select count(*) from colors))+1 as color_num 
   from employees
)

-- get both tables joined by color_num   
select e.employee, 
       c.color
  from e 
  join c on c.color_num = e.color_num

<强>输出:

employee  color
---------------
    John    Red
    Jack  Green
   April   Blue
   Sonny    Red
    Jill  Green
    Jane   Blue

答案 2 :(得分:0)

这可以通过使用NTILE函数在MS SQL中使用ROW_NUMBER()函数来实现。 NTILE解决方案分发数据,但不像预期结果那样分配给定订单。

结果:

Sam - Red
John - Green
Jack - Blue
April - Red
Sonny - Green
Jill - Blue
Jane - Red

但是这个解决方案按预期提供输出。

DECLARE @Employees TABLE
(
       Name VARCHAR(10)
)

INSERT INTO @Employees (Name) 
VALUES ('Sam'), ('John'), ('Jack'), ('April'), ('Sonny'), ('Jill'), ('Jane');

DECLARE @Colors TABLE
(
       Name VARCHAR(10)
)

INSERT INTO @Colors (Name) 
VALUES ('Red'), ('Green'), ('Blue');

DECLARE @ColorCount INT
SELECT @ColorCount = COUNT(*) FROM @Colors

;WITH Employees(SNumber, Name) AS
(
       SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS SNumber, Name
       FROM @Employees
    ), 
    Colors(CNumber, Name) AS
    (
       SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS CNumber, Name 
       FROM @Colors 
    )

SELECT E.Name, C.Name FROM Employees E
INNER JOIN Colors C ON 
       CASE 
       WHEN (E.SNumber % @ColorCount) = 0 
            THEN @ColorCount 
            ELSE E.SNumber % @ColorCount 
       END = C.CNUmber

结果:

Sam - Red
April - Red    
Jane - Red
John - Green
Sonny - Green
Jack - Blue
Jill - Blue