【问题标题】:How can I randomly do a partial outer join in SQL如何在 SQL 中随机执行部分外连接
【发布时间】:2017-05-16 18:32:35
【问题描述】:

我有两个单列表,A 和 B。我想创建一个新表,其中 A 的每个元素都与 B 中的 3 个随机元素的样本配对,即:

表A:

A1  
A2  
A3   

表 B:

B1  
B2  
B3  
...  
B100

结果表C:

A1 B51  
A1 B63  
A1 B17   
A2 B62    
A2 B13    
A2 B17  
A3 B1  
A3 B69  
A3 B78

对于每个 A,B 的值是随机的。重复/重叠对于不同的 As 是可以的,但对于给定的 A 则不行(即每个 A 必须与 B 的 3 个唯一元素配对,但不同的 As 可以具有相同的元素B;也就是说,不同的 As 极不可能有相同的 B 集)。有没有办法在 A 的元素上不使用 for 循环来做到这一点?

【问题讨论】:

  • 您使用的是哪个 DBMS?
  • 也许是FROM A cross apply (Select top 10 FROM B order by random()),但这取决于dbms
  • 我们正在使用 SQL Server
  • 是的,2008 年。需要为每个项目设置不同的 10 条记录
  • B 的预期输出样本将有助于澄清问题。

标签: sql sql-server


【解决方案1】:

我认为最简单的方法可能是outer apply:

select a.*, b.*
from a outer apply
     (select top 3 b.*
      from b
      where b.id <> a.id   -- just needed to prevent correlation "optimization"
      order by newid()
     ) b;

我确实强调“简单”。对于较大的b 表,Ross 的解决方案可能更快。

【讨论】:

  • 再一次,我认为这会重复项目——A 的每个项目都会从 B 获得相同的项目。
  • @RossPresser 。 . .这是可能的,但前提是 SQL Server 优化了对子查询的重复调用。反过来,这可以通过添加相关条件来解决。
  • 您是使用 PK 表中的 id 还是建议创建一个 row_number() id ?我担心如果 id 与 A 相同,您无法从 B 中选择
  • @JuanCarlosOropeza 。 . .我不明白你的评论。这个答案没有row_number()。它确实有一个毫无价值的关联子句,应该确保关联的子查询运行多次。
  • @GurwinderSingh 不知道这是否有帮助,但在 rextester 工作正常
【解决方案2】:

这可以做到,但速度不是很快。假设 F1 是 A 的主键(或至少是 A 的某个唯一键),而 F2 是您想要 B 的值(主键与否):

WITH X AS (
   SELECT A.F1,  ROW_NUMBER() OVER (ORDER BY A.F1) AS N
   FROM A
), Y AS (
   SELECT B.F2, ROW_NUMBER() OVER (ORDER BY NEWID()) AS N
   FROM B
) 
SELECT A.F1, B.F2
FROM X INNER JOIN Y ON Y.N BETWEEN (X.N-1)*10+1 and ((X.N)*10)

编辑:修正一个错误。现在对 X.N=1 使用 Y.N=1..10,对 X.N=2 使用 Y.N=11..20,等等。

【讨论】:

  • 我尝试测试您的功能,但不起作用。你能检查一下吗here
  • 更新了答案。请注意,您的 B 表只有 15 个项目,因此不能满足所有 5 个 A 项目。 (我试图提供一个更新的测试,但我的更改没有坚持下去;我对那个测试站点不是很熟悉。)
  • 我的回答假设您需要为每个 A 提供唯一的 B 项。您更新的问题澄清了这不是必需的。由于这种误解,我“击落”的两个答案将满足您的需求。
  • 我知道 OP 需要 10 个随机 B 用于每个 A 行。但是 B 中的一项可以出现多次,约束是不要对所有 A 使用相同的 10 个随机 B。
  • 你不需要假设 F1 是 tableA 的 PK,只需使用 row_number 中的 N。
【解决方案3】:

我相信这行得通:

    ;
    WITH    RandomBs
              AS ( SELECT c.ClientId AS val
                    ,   ROW_NUMBER() OVER ( ORDER BY ( SELECT NEWID() ) ) rn
                    FROM Clients c),
            A AS ( SELECT DO.OrganizationId
                    ,   ROW_NUMBER() OVER ( ORDER BY ( SELECT NULL ) ) rn
                    FROM Organizations DO)
        SELECT *
            FROM A
                CROSS APPLY ( SELECT val
                                FROM RandomBs
                                WHERE rn BETWEEN ( ( ( A.rn - 1 ) * 10 ) + 1 ) AND ( (A.rn * 10) ) ) x

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-05
    • 1970-01-01
    • 1970-01-01
    • 2013-06-04
    • 2014-11-26
    • 2018-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多