0

我有以下问题:

设想:

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

假设我有一个项目表。

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 |

在这里,价格 1将匹配具有任何购买者 ID 和 的项目,unit_id = 1价格2status_id = 2将匹配具有和的数学项目。价格 3将匹配带有 any 、 any和的项目。buyer_id = 1unit_id = 1status_id = 2buyer_idunit_idstatus_id = 3

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

我们可以假设没有多个价格与完全相同的价格组匹配(所有价格都有唯一的buyer_id,unit_id和组合status_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 = 1我们将得到两行:unit_id = 1status_id = 2

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

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

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

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

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

更新

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

4

1 回答 1

0

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

因为我有一小部分可能的组合,所以相对容易形成一个CASE子句来为每个组合提供数值来表示不同组合的顺序。接下来,我们将为每个 item_id 选择具有最小选择器值的行。这是通过加入简单的组标识符 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
于 2013-03-20T20:25:40.167 回答