将特定数量的行从一个 table 连接到另一个行的单行
Join specific number of rows from one table to a single row of another one
我目前正在生成随机数据,但我不确定如何执行这一部分。
我有两个 table。我有一个实体 table 和一个组 table。两个 table 都有唯一的标识符 (guid)。我的目标是创建一个 table 映射,将实体 X 次匹配到单个组。
例如,假设我有 10k 个实体和 100 个组,我想创建 1k 个映射。我需要为每个组 (1000/100) 创建 10 个映射。我可以继续创建一个 while 循环,只得到 10 个随机实体,但效率不高,我想避免这种情况。我也想过cross join然后把结果缩减到1k,但是我希望每组有完全相同数量的映射。
有没有办法通过单个查询来完成此操作?
这是一个例子,假设我有这个 Group table
和 Entity Table
+---------+
| GroupId |
+---------+
| G1 |
| G2 |
| G3 |
+---------+
+----------+
| EntityId |
+----------+
| E1 |
| E2 |
| E3 |
| E4 |
| E5 |
| E6 |
| E7 |
| E8 |
| E9 |
| E10 |
+----------+
I would like to get 6 mappings (so each group needs 2 mappings). Here is an example of what I could get:
+---------+----------+
| GroupId | EntityId |
+---------+----------+
| G1 | E2 |
| G1 | E4 |
| G2 | E9 |
| G2 | E10 |
| G3 | E2 |
| G3 | E5 |
+---------+----------+
这听起来很适合 NTILE。
首先使用 ROW_NUMBER() on the Groups
table to generate sequential "group numbers" (sort by NewID() 作为 相对 随机顺序):
GroupId | GroupNum
:------ | -------:
G3 | 1
G2 | 2
G1 | 3
然后使用 NTILE() 将 Entity
行分配到所需数量的组中:
E1 | GroupNum
:-- | -------:
E2 | 1
E10 | 1
E3 | 1
E4 | 1
E1 | 2
E6 | 2
E5 | 2
E7 | 3
E8 | 3
E9 | 3
最后在“组号”上将结果合并在一起:
SQL:
DECLARE @NumOfGroups INT;
SET @NumOfGroups = ( SELECT COUNT(*) FROM Groups );
SELECT e.[E1], g.GroupId
FROM (
SELECT *, NTILE(@NumOfGroups) OVER(ORDER BY NEWID()) AS GroupNum
FROM Entities
)
AS e
INNER JOIN
(
SELECT *, ROW_NUMBER() OVER(ORDER BY NEWID()) AS GroupNum
FROM Groups
)
AS g ON g.GroupNum = e.GroupNum
ORDER BY e.GroupNum, e.E1
GO
结果:
E1
GroupId
E1
G1
E3
G1
E5
G1
E8
G1
E2
G3
E7
G3
E9
G3
E10
G2
E4
G2
E6
G2
db<>fiddle here
注意:如果 Entity
行少于 Groups
,显然这种方法将不起作用,但这听起来不像是这里的问题
我目前正在生成随机数据,但我不确定如何执行这一部分。 我有两个 table。我有一个实体 table 和一个组 table。两个 table 都有唯一的标识符 (guid)。我的目标是创建一个 table 映射,将实体 X 次匹配到单个组。
例如,假设我有 10k 个实体和 100 个组,我想创建 1k 个映射。我需要为每个组 (1000/100) 创建 10 个映射。我可以继续创建一个 while 循环,只得到 10 个随机实体,但效率不高,我想避免这种情况。我也想过cross join然后把结果缩减到1k,但是我希望每组有完全相同数量的映射。
有没有办法通过单个查询来完成此操作?
这是一个例子,假设我有这个 Group table
和 Entity Table
+---------+
| GroupId |
+---------+
| G1 |
| G2 |
| G3 |
+---------+
+----------+
| EntityId |
+----------+
| E1 |
| E2 |
| E3 |
| E4 |
| E5 |
| E6 |
| E7 |
| E8 |
| E9 |
| E10 |
+----------+
I would like to get 6 mappings (so each group needs 2 mappings). Here is an example of what I could get:
+---------+----------+
| GroupId | EntityId |
+---------+----------+
| G1 | E2 |
| G1 | E4 |
| G2 | E9 |
| G2 | E10 |
| G3 | E2 |
| G3 | E5 |
+---------+----------+
这听起来很适合 NTILE。
首先使用 ROW_NUMBER() on the Groups
table to generate sequential "group numbers" (sort by NewID() 作为 相对 随机顺序):
GroupId | GroupNum :------ | -------: G3 | 1 G2 | 2 G1 | 3
然后使用 NTILE() 将 Entity
行分配到所需数量的组中:
E1 | GroupNum :-- | -------: E2 | 1 E10 | 1 E3 | 1 E4 | 1 E1 | 2 E6 | 2 E5 | 2 E7 | 3 E8 | 3 E9 | 3
最后在“组号”上将结果合并在一起:
SQL:
DECLARE @NumOfGroups INT; SET @NumOfGroups = ( SELECT COUNT(*) FROM Groups ); SELECT e.[E1], g.GroupId FROM ( SELECT *, NTILE(@NumOfGroups) OVER(ORDER BY NEWID()) AS GroupNum FROM Entities ) AS e INNER JOIN ( SELECT *, ROW_NUMBER() OVER(ORDER BY NEWID()) AS GroupNum FROM Groups ) AS g ON g.GroupNum = e.GroupNum ORDER BY e.GroupNum, e.E1 GO
结果:
E1 | GroupId |
---|---|
E1 | G1 |
E3 | G1 |
E5 | G1 |
E8 | G1 |
E2 | G3 |
E7 | G3 |
E9 | G3 |
E10 | G2 |
E4 | G2 |
E6 | G2 |
db<>fiddle here
注意:如果 Entity
行少于 Groups
,显然这种方法将不起作用,但这听起来不像是这里的问题