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

How can I evenly distribute rows in one table to rows in another table in TSQL?

我正在尝试找出一个 SQL 查询,它将记录从一个 table 均匀分布或分配给另一个 table。解释它的最好方法是通过一个人为的例子。

假设我有 table 名员工,我想为每个员工分配 table 种颜色中的一种颜色。

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

员工:

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 中构造此连接?

我认为您想使用带有颜色数参数的 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

我知道问题是关于 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

这可以通过在 MS SQL 中使用 ROW_NUMBER() 函数而不使用 NTILE 函数来实现。 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