SQL 仅在第一场比赛中加入

SQL Joining on first match only

我正在尝试编写一个 SQL 语句,该语句使用 INNER JOIN 来相互匹配出价和报价。

我有一个出价 table,如下所示

+-------------------------+-------------------+--------------------------------+--------------------------------+
| bid_id                  | user_id           | bid_volume                     | bid_price                      |
+-------------------------+-------------------+--------------------------------+--------------------------------+
|                     101 |                 1 |                       100.0000 |                       300.0000 |
|                     102 |                 2 |                       200.0000 |                        20.0000 |
|                     103 |                 3 |                        50.0000 |                        40.0000 |
|                     104 |                 4 |                        60.0000 |                       100.0000 |
|                     105 |                 5 |                        75.0000 |                        90.0000 |
+-------------------------+-------------------+--------------------------------+--------------------------------+

我有一个报价 table 如下所示

+---------------------------+-------------------+----------------------------------+----------------------------------+
| offer_id                  | user_id           | offer_volume                     | offer_price                      |
+---------------------------+-------------------+----------------------------------+----------------------------------+
|                        91 |                 6 |                          60.0000 |                         100.0000 |
|                        92 |                 7 |                          75.0000 |                          85.0000 |
|                        93 |                 8 |                         100.0000 |                         200.0000 |
|                        94 |                 9 |                          75.0000 |                        1000.0000 |
|                        95 |                10 |                         100.0000 |                         300.0000 |
+---------------------------+-------------------+----------------------------------+----------------------------------+

我正在尝试匹配出价和出价,应该是一对一的关系,即只有一个出价可以与一个出价匹配。如果有两方或多方出价,则最高出价也应该是获胜者。

如果 bid_volumeoffer_volumebid_price >= offer_price 匹配并且它是所有出价中最高的 bid_price,则该出价应该是中标。

我按 bid_price 从高到低对出价进行排序,因此首先处理最高出价。当一个出价匹配多个出价时,就会出现问题。

取出价101以上的数据将满足出价9395。它实际上应该只与报价 93 匹配,因为它是较低的价格。

下面是我的 SQL 的开始,但它限制了我真正坚持的比赛,所以出价与报价是一对一的关系。

SELECT  
    Bids.user_id AS bidder_user_id,
    Offers.user_id AS dealer_user_id,
    Bids.bid_volume,
    Offers.offer_volume,
    Bids.bid_price, 
    Offers.offer_price
FROM  
    Bids
INNER JOIN 
    Offers
ON
    /* Volume - Volume must be equal*/
    Bids.bid_volume =
    Offers.offer_volume   AND
    /* Price - Bid price greater than or equal to offer price*/ 
    Bids.bid_price  >=
    Offers.offer_price
ORDER BY 
    bid_price DESC;

上面的输出如下所示(注意有两个匹配 bidder_user_id = 1 试图只得到一个)

+----------------+----------------+------------+--------------+-----------+-------------+
| bidder_user_id | dealer_user_id | bid_volume | offer_volume | bid_price | offer_price |
+----------------+----------------+------------+--------------+-----------+-------------+
|              1 |              8 |   100.0000 |     100.0000 |  300.0000 |    200.0000 |
|              1 |             10 |   100.0000 |     100.0000 |  300.0000 |    300.0000 |
|              4 |              6 |    60.0000 |      60.0000 |  100.0000 |    100.0000 |
|              5 |              7 |    75.0000 |      75.0000 |   90.0000 |     85.0000 |
+----------------+----------------+------------+--------------+-----------+-------------+

所需的输出如下所示,因此用户 1 出价与两个出价不匹配,但我不确定如何将内部连接限制为仅在第一次出现时匹配。

+----------------+----------------+------------+--------------+-----------+-------------+
| bidder_user_id | dealer_user_id | bid_volume | offer_volume | bid_price | offer_price |
+----------------+----------------+------------+--------------+-----------+-------------+
|              1 |              8 |   100.0000 |     100.0000 |  300.0000 |    200.0000 |
|              4 |              6 |    60.0000 |      60.0000 |  100.0000 |    100.0000 |
|              5 |              7 |    75.0000 |      75.0000 |   90.0000 |     85.0000 |
+----------------+----------------+------------+--------------+-----------+-------------+

Is this how you did it?

SELECT  
    Bids.user_id AS bidder_user_id,
    Offers.user_id AS dealer_user_id,
    Bids.bid_volume,
    Offers.offer_volume,
    Bids.bid_price, 
    Offers.offer_price,
    COUNT(Bids.user_id)
FROM  
    Bids
INNER JOIN 
    Offers
ON
    /* Volume - Volume must be equal*/
    Bids.bid_volume =
    Offers.offer_volume   AND
    /* Price - Bid price greater than or equal to offer price*/ 
    Bids.bid_price  >=
    Offers.offer_price
ORDER BY 
    bid_price DESC
GROUP BY
    Bids.user_id;

如果你的MySql版本是8.0+你可以在tableOffers中使用ROW_NUMBER()window函数得到最低的行offer_price 每个 offer_volume 然后加入 Bids:

SELECT  
    b.user_id AS bidder_user_id,
    o.user_id AS dealer_user_id,
    b.bid_volume,
    o.offer_volume,
    b.bid_price, 
    o.offer_price
FROM  Bids b 
INNER JOIN (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY offer_volume ORDER BY offer_price) rn 
  FROM Offers 
) o
ON b.bid_volume = o.offer_volume AND b.bid_price >= o.offer_price
WHERE o.rn = 1
ORDER BY b.bid_price DESC;

对于以前的版本,您可以使用 NOT EXISTS:

SELECT  
    b.user_id AS bidder_user_id,
    o.user_id AS dealer_user_id,
    b.bid_volume,
    o.offer_volume,
    b.bid_price, 
    o.offer_price
FROM  Bids b 
INNER JOIN (
  SELECT o1.* FROM Offers o1
  WHERE NOT EXISTS (
    SELECT 1 FROM Offers o2 
    WHERE o2.offer_volume = o1.offer_volume AND o2.offer_price < o1.offer_price
  )
) o
ON b.bid_volume = o.offer_volume AND b.bid_price >= o.offer_price
ORDER BY b.bid_price DESC;

参见demo