如何在 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
我正在尝试找出一个 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