【问题标题】:Selecting the right row from multiple matching rows in MySQL从 MySQL 中的多个匹配行中选择正确的行
【发布时间】:2013-02-06 09:59:03
【问题描述】:

我有以下问题:

场景:

我已经重组了表格结构以指出问题并隐藏不相关的细节。

假设我有一个项目表。

Item: item_id | buyer_id | unit_id | status_id 

所有列都有一个非空值引用对应的表。

我拥有的其他表是具有以下结构的价格目录:

Price: price_id | buyer_id | unit_id | status_id | price

这里的任何引用值都可以具有值“-1”,意思是“全部”。所以我们可以在价格表中有以下行:

| price_id | buyer_id | unit_id | status_id | price |
|        1 |       -1 |       1 |         2 |    15 |
|        2 |        1 |       1 |         2 |    25 |
|        3 |       -1 |      -1 |         3 |    13 |

这里 price 1 将匹配具有任何购买者 ID 的项目,unit_id = 1status_id = 2price 2 将匹配具有 buyer_id = 1unit_id = 1 和 @ 的项目987654329@。 价格 3 将匹配任何buyer_id、任何unit_idstatus_id = 3 的项目。

如果有多个价格与一个项目匹配,则使用以下逻辑完成选择:获取指定字段最多的价格(-1 值的最少数量)。如果有多个价格具有相同数量的 -1 值,那么我们会在 buyer_id 中选择一个值不同于 -1 的价格。如果不存在,我们会在unit_id 处选择具有“非 -1”值的那个,并在状态处选择具有“非 -1”值的那个。

我们可以假设没有多个价格与完全相同的一组价格匹配(所有价格都有buyer_idunit_idstatus_id 的唯一组合。)

问题:

现在我需要进行查询,为项目表中的每个项目选择正确的价格。到目前为止,我得到了这个:

选择 item_id,价格 来自项目 INNER JOIN 价格 ON 1=1 AND(price.buyer_id = item.buyer_id 或 price.buyer_id = -1) AND (price.unit_id = item.unit_id 或 price.unit_id = -1) AND(price.status_id = item.status_id 或 price.status_id = -1)

基本上这将获得所有匹配的价格。因此,如果我们有 buyer_id = 1unit_id = 1status_id = 2 的项目,我们将得到两行:

| item_id |价格 | | 1 | 15 | | 1 | 25 |

我的第一个想法是使用GROUP BY,但我还没有弄清楚如何做到这一点,以便选择正确的价格,而不仅仅是随机/第一个(?)一个。

编辑:尝试对行进行排序 (ORDER BY buyer_id DESC, unit_id DESC, status_id DESC),然后根据排序的子查询对结果进行分组,但似乎排序方式不起作用。

那么如何在GROUP BY 中选择正确的行?或者,通过单个查询(子查询很好)获得正确价格的替代解决方案是什么?

在这种特殊情况下,改变表结构并不是一个真正的选择。

更新

我一直在使用the solution 我之前提交的,但是选择价格的标准数量从三个增加到五个。这意味着我目前在我的CASE WHEN 结构中有一个包含 32 种不同组合的列表。万一我需要添加另一个,列表将再次翻倍,所以我仍在寻找更好的解决方案。

【问题讨论】:

    标签: mysql group-by inner-join


    【解决方案1】:

    目前问题已解决如下。它完成了这项工作,至少在特定情况下执行得足够快,但我希望存在更好的解决方案。现在这就是诀窍。

    因为我有相当少的可能组合,所以形成一个CASE 子句来为每个组合提供数值以表示不同组合的顺序相对容易。接下来,我们将为每个 item_id 选择具有最小选择器值的行。这是由Joining with simple group-identifier, max-value-in-group Sub-query 完成的。这里有一个查询来展示这个想法:

    SELECT item_id, price
    FROM (
        SELECT item_id, price,
            CASE
                WHEN price.buyer_id <> -1 AND price.unit_id <> -1 AND price.status_id <> -1 THEN 1
                WHEN price.buyer_id <> -1 AND price.unit_id <> -1 AND price.status_id =  -1 THEN 2
                WHEN price.buyer_id <> -1 AND price.unit_id =  -1 AND price.status_id <> -1 THEN 3
                WHEN price.buyer_id <> -1 AND price.unit_id =  -1 AND price.status_id =  -1 THEN 4
                WHEN price.buyer_id =  -1 AND price.unit_id <> -1 AND price.status_id <> -1 THEN 5
                WHEN price.buyer_id =  -1 AND price.unit_id <> -1 AND price.status_id =  -1 THEN 6
                WHEN price.buyer_id =  -1 AND price.unit_id =  -1 AND price.status_id <> -1 THEN 7
                WHEN price.buyer_id =  -1 AND price.unit_id =  -1 AND price.status_id =  -1 THEN 8
            END AS selector
        FROM item
            INNER JOIN price ON 1=1
                AND (price.buyer_id = item.buyer_id OR price.buyer_id = -1)
                AND (price.unit_id = item.unit_id OR price.unit_id = -1)
                AND (price.status_id = item.status_id OR price.status_id = -1) 
        ) AS all_possible_prices
    
        INNER JOIN (
        SELECT item_id, MIN(selector)
        FROM (
            SELECT item_id
                CASE
                    WHEN price.buyer_id <> -1 AND price.unit_id <> -1 AND price.status_id <> -1 THEN 1
                    WHEN price.buyer_id <> -1 AND price.unit_id <> -1 AND price.status_id =  -1 THEN 2
                    WHEN price.buyer_id <> -1 AND price.unit_id =  -1 AND price.status_id <> -1 THEN 3
                    WHEN price.buyer_id <> -1 AND price.unit_id =  -1 AND price.status_id =  -1 THEN 4
                    WHEN price.buyer_id =  -1 AND price.unit_id <> -1 AND price.status_id <> -1 THEN 5
                    WHEN price.buyer_id =  -1 AND price.unit_id <> -1 AND price.status_id =  -1 THEN 6
                    WHEN price.buyer_id =  -1 AND price.unit_id =  -1 AND price.status_id <> -1 THEN 7
                    WHEN price.buyer_id =  -1 AND price.unit_id =  -1 AND price.status_id =  -1 THEN 8
                END AS selector
            FROM item
                INNER JOIN price ON 1=1
                    AND (price.buyer_id = item.buyer_id OR price.buyer_id = -1)
                    AND (price.unit_id = item.unit_id OR price.unit_id = -1)
                    AND (price.status_id = item.status_id OR price.status_id = -1) ) AS min_seeds
        GROUP BY item_id
        ) AS min_selectors ON all_possible_prices.item_id = min_selectors.item_id 
                                AND all_possible_prices.selector = min_selectors.selector
    

    【讨论】:

      猜你喜欢
      • 2012-10-09
      • 2014-06-23
      • 1970-01-01
      • 2012-12-25
      • 2013-12-26
      • 2015-05-23
      • 1970-01-01
      • 1970-01-01
      • 2022-11-15
      相关资源
      最近更新 更多