【问题标题】:Getting mutual matches in SQL Server在 SQL Server 中获取相互匹配
【发布时间】:2015-06-16 00:33:52
【问题描述】:

我想匹配买家和卖家。我这样做是为了让它尽可能简单。

我有一张桌子:tmpSales。在其中,我有一个 TransID、BuyerID、SellerID、Item 和 Date。

有时买家也是卖家,反之亦然。

我想要的是一个买家卖给卖家,而同一卖家卖给同一买家的记录。

我有这个查询,它工作正常:

SELECT *
FROM [dbo].[tmpSales] T1
INNER JOIN [dbo].[tmpSales] T2
ON T1.[BuyerID] = T2.[SellerID]
AND T2.[BuyerID] = T1.[SellerID]

但是,它为每个匹配返回 2 条记录。有没有办法返回一条记录,同时存在 BuyerID 和 SellerID?

示例数据如下所示:

TransID     BuyerID     SellerID      ItemID      Date
1           10012       10032          65         10/15/2014
2           11111       10012          120        12/15/2014
3           10032       10012          32         2/2/2015
4           11111       10032          30         2/10/2015
5           10012       11111          45         3/1/2015  

在这种情况下,我可以看到 1001210032 都相互买卖,10012 也是如此>11111。我只想要这样的东西:

ID1             ID2
10012           10032
10012           11111

数据将不断增长,因此它必须是动态的(即我不能在代码中添加“Where BuyerID = '10012'”之类的内容)。

编辑:实际上,我想做的是把它变成一个视图或存储过程,并将 2 个 ID 传递给它,让它告诉我是否存在相互匹配。

【问题讨论】:

  • 其实很简单,要么用 CTE/Derived table 解决方案,要么用 WHERE EXISTS() 解决方案。
  • 只是为了添加@TabAlleman 所说的内容,以避免在每场比赛中获得两条记录(即买家 1 与卖家 2,买家 2 与卖家 1),只需使用 WHERE 子句断言BuyerId < SellerId (反之亦然),您每场比赛只会获得一条记录。如果有多个可能的 macthe,请使用 SELECT DISTINCT

标签: sql sql-server


【解决方案1】:

您可以通过选择哪个是第一个来轻松地将选择中的数据限制为一种方式,如下所示:

SELECT *
FROM [dbo].[tmpSales] T1
INNER JOIN [dbo].[tmpSales] T2
ON T1.[BuyerID] = T2.[SellerID]
AND T2.[BuyerID] = T1.[SellerID]
AND T2.[BuyerID] > T1.[BuyerID]

所以这样一来,具有较大买家 ID 的那个总是作为第二个 - 你也可以在一个过程中拥有类似的逻辑。

【讨论】:

  • 这样你当然不会有两次交易细节,只有单向交易,但你似乎不需要那个
  • 这里有很多很好的答案,但这个最直接,适合我的需要。谢谢!
【解决方案2】:

您可以使用以下查询来检索所有相互映射

SELECT DISTINCT T.BuyerID AS ID1,T.SellerID AS ID2
FROM [dbo].[tmpSales] T
WHERE EXISTS (SELECT * 
              FROM [dbo].[tmpSales] T1
              WHERE T1.BuyerID = T.SellerId
                    AND T1.SellerID = T.BuyerID)

如果你只想检查指定的一对,你也可以这样做

DECLARE @Id1 INT
DECLARE @Id2 INT
SELECT *
FROM [dbo].[tmpSales] T
WHERE T.BuyerID = @Id1
AND T.SellerID = @Id2
AND EXISTS (SELECT * 
            FROM [dbo].[tmpSales] T1
            WHERE T1.BuyerID = @Id2
                AND T1.SellerID = @Id1)

【讨论】:

    【解决方案3】:

    这是在 MySql 中,但同样的原则也适用。

    此查询获取在两个人之间进行的交易的所有不同用户,他们在不同的交易中都是买方和卖方。由于这包括所有交易,每个参与者将被列出两次(一次作为买方,一次作为卖方 - 如果在任一方向上都有不止一次销售,则会被列出更多次而没有“不同”)。

    select
        distinct sale1.buyer_id party1, sale1.seller_id party2
    from
        temp_sale sale1
        join temp_sale sale2 on sale1.buyer_id = sale2.seller_id and sale1.seller_id = sale2.buyer_id
    ;
    

    这给出了这些行:

    + ----------- + ----------- +
    | party1      | party2      |
    + ----------- + ----------- +
    | 10032       | 10012       |
    | 10012       | 11111       |
    | 10012       | 10032       |
    | 11111       | 10012       |
    + ----------- + ----------- +
    4 rows
    

    添加下面的 where 子句将为您提供相互买卖的不同个体。

    select
        distinct sale1.buyer_id party1, sale1.seller_id party2
    from
        temp_sale sale1
        join temp_sale sale2 on sale1.buyer_id = sale2.seller_id and sale1.seller_id = sale2.buyer_id
    where 
        sale1.buyer_id > sale1.seller_id
    ;
    

    这给出了这些行:

    + ----------- + ----------- +
    | party1      | party2      |
    + ----------- + ----------- +
    | 10032       | 10012       |
    | 11111       | 10012       |
    + ----------- + ----------- +
    2 rows
    

    为了完整起见,以下是整个示例:

    use example;
    
    drop table if exists temp_sale;
    
    create table temp_sale (
        id int,
        buyer_id int,
        seller_id int,
        item_id int,
        date date
    );
    
    insert into temp_sale values (1, 10012, 10032, 65, '2014-10-15');
    insert into temp_sale values (2, 11111, 10012, 120, '2014-12-15');
    insert into temp_sale values (3, 10032, 10012, 32, '2015-02-02');
    insert into temp_sale values (4, 11111, 10032, 30, '2015-02-10');
    insert into temp_sale values (5, 10012, 11111, 45, '2015-03-01');
    
    select
        distinct sale1.buyer_id party1, sale1.seller_id party2
    from
        temp_sale sale1
        join temp_sale sale2 on sale1.buyer_id = sale2.seller_id and sale1.seller_id = sale2.buyer_id
    ;
    
    select
        distinct sale1.buyer_id party1, sale1.seller_id party2
    from
        temp_sale sale1
        join temp_sale sale2 on sale1.buyer_id = sale2.seller_id and sale1.seller_id = sale2.buyer_id
    where 
        sale1.buyer_id > sale1.seller_id
    ;
    

    【讨论】:

      【解决方案4】:

      哦...这是一个非常有趣的问题,以至于有 3 个人比我先到了这里。在任何情况下,我建议随着数据集的增长将此数据记录到表中,而不是每次想要查看时都运行临时查询,但是对于初始数据填充,这是我拼凑的一个粗略的小光标。希望对您有所帮助!

      if object_id(N'tempdb..#FindMe') is not null
          drop table #FindMe ;
      
      if object_id(N'tempdb..#UniqueRelationships') is not null
          drop table #UniqueRelationships ;
      
      create table #UniqueRelationships
          ( Id1 int,
          Id2 int );
      
      declare @Table table 
          ([TransID] int not null 
          ,[BuyerID] int not null 
          ,[SellerID] int not null 
          ,[ItemID] int not null 
          ,[Date] date not null );
      
      insert @table values 
          (1,10012,10032,65,'2014-10-15 00:00:00.0'),
          (2,11111,10012,120,'2014-12-15 00:00:00.0'),
          (3,10032,10012,32,'2015-02-02 00:00:00.0'),
          (4,11111,10032,30,'2015-02-10 00:00:00.0'),
          (5,10012,11111,45,'2015-03-01 00:00:00.0');
      
      select 
          t1.BuyerID
          ,t1.SellerID
      into #FindMe 
      from @table t1
      join @Table t2 on t1.BuyerID = t2.SellerID
        and t2.BuyerID = t1.SellerID ;
      
      declare
          @IdA int,
          @IdB int;
      
      declare FindMe cursor for
          select BuyerId, SellerId from #FindMe ;
      
      open FindMe ;
      fetch next from FindMe into @IdA, @IdB ;
      while @@fetch_status = 0
      begin
          if not exists( select 1 
                          from #UniqueRelationships 
                          where ( Id1 = @IdA
                            and Id2 = @IdB ) 
                          or ( Id2 = @IdA
                            and Id1 = @IdB ) )
          begin
              insert #UniqueRelationships 
                  ( Id1, Id2 )
              select 
                  @IdA
                  ,@IdB
          end
      
          fetch next from FindMe into @IdA, @IdB ;
      end ;
      close FindMe ;
      deallocate FindMe ;
      
      select * from #UniqueRelationships ;
      
      if object_id(N'tempdb..#FindMe') is not null
          drop table #FindMe ;
      
      if object_id(N'tempdb..#UniqueRelationships') is not null
          drop table #UniqueRelationships ;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-17
        • 2019-04-25
        • 1970-01-01
        • 1970-01-01
        • 2019-12-07
        相关资源
        最近更新 更多