MySQL选择行取决于特定列是否存在特定值

时间:2015-04-17 02:35:50

标签: mysql sql subquery

我有一个非常具体的问题,我一直在努力争取解决它没有运气。

基本上,我想要实现的是根据货币价值从定价表'product_line_price'中获得最低价格。诀窍在于product_line_price表并不总是包含特定货币的值,在这种情况下,它必须默认选择默认的“AUD”货币。此表还包含每个产品的多个记录,具有不同的定价方案,但我只对我所查询的特定货币的最便宜(最低价格)感兴趣。

最终目标用于产品的“分面搜索”,用户可以选择价格范围来列出特定范围内的产品。

这是我尝试的整体查询,我认为这是最接近的尝试:

SELECT    * 
FROM      product_line 
LEFT JOIN 
          ( 
                   SELECT   idproduct_line, 
                            idprice_group, 
                            CASE 
                                     WHEN EXISTS 
                                              ( 
                                                     SELECT currency_code 
                                                     FROM   product_line_price 
                                                     WHERE  currency_code = 'GBP' 
                                                     AND    idproduct_line = product_line_price.idproduct_line) THEN Min(price)
                                     ELSE Min(price)*0.5098 
                            END AS userprice 
                   FROM     product_line_price 
                   WHERE    !deleted 
                   AND 
                            CASE 
                                     WHEN EXISTS 
                                              ( 
                                                     SELECT currency_code 
                                                     FROM   product_line_price 
                                                     WHERE  currency_code = 'GBP' 
                                                     AND    idproduct_line = product_line_price.idproduct_line) THEN currency_code = 'GBP'
                                     ELSE currency_code = 'AUD' 
                            END 
                   GROUP BY idproduct_line 
                   ORDER BY product_line_price.idproduct_line ASC) AS product_line_price 
ON        product_line.idproduct_line = product_line_price.idproduct_line 
WHERE     !product_line.deleted 
AND       product_line.idproduct_line_status = 1 
AND       product_line.idproduct_line IN 
          ( 
                 SELECT `idproduct_line` 
                 from   `product_line_has_product_category` 
                 where  `idproduct_category` = '103') 
AND       (( 
                              product_line_price.idprice_group IN 
                              ( 
                                     SELECT `idprice_group` 
                                     FROM   `price_group` 
                                     WHERE  !`deleted` 
                                     AND    `PUBLIC` 
                                     AND    `active`)) 
          AND       ( 
                              userprice <= 250)) 
ORDER BY  product_line.idproduct_line ASC

我遇到问题的子查询就是这个:

SELECT   idproduct_line, 
                            idprice_group, 
                            CASE 
                                     WHEN EXISTS 
                                              ( 
                                                     SELECT currency_code 
                                                     FROM   product_line_price 
                                                     WHERE  currency_code = 'GBP' 
                                                     AND    idproduct_line = product_line_price.idproduct_line) THEN Min(price)
                                     ELSE Min(price)*0.5098 
                            END AS userprice 
                   FROM     product_line_price 
                   WHERE    !deleted 
                   AND 
                            CASE 
                                     WHEN EXISTS 
                                              ( 
                                                     SELECT currency_code 
                                                     FROM   product_line_price 
                                                     WHERE  currency_code = 'GBP' 
                                                     AND    idproduct_line = product_line_price.idproduct_line) THEN currency_code = 'GBP'
                                     ELSE currency_code = 'AUD' 
                            END 
                   GROUP BY idproduct_line 
                   ORDER BY product_line_price.idproduct_line ASC

因此,我需要能够检索GBP货币的值(如果存在),否则默认为AUD货币(并应用货币转换)。这里的一些数字是用于测试的硬编码,稍后将通过变量提供。

我有一种感觉,使用上面的子查询,EXISTS子查询没有正确使用idproduct_line值,因为当我运行它时,我只获得GBP结果,即使该表中有大量记录没有GBP结果。我正在谈论的子查询就是这个:

SELECT currency_code 
FROM   product_line_price 
WHERE  currency_code = 'GBP' 
AND    idproduct_line = product_line_price.idproduct_line

谁能看到我哪里出错了?我觉得我很亲密,但是那个子查询中的某些内容是错误的,而SQL并不是我最强的套装。

编辑1:

我主要关心的是包含EXISTS子句的子查询,我知道其余部分都可以工作,并且纯粹为了上下文目的提供了整个查询。

您可以从以下链接下载有问题的表的转储和一些示例数据。样本数据包含3种产品的定价,一种仅具有AUD定价,一种具有AUD和GBP定价,另一种具有多种货币定价。 https://www.dropbox.com/s/h1i23f5ac2jmrvn/product_line_price.sql?dl=0

我针对此数据运行的查询是:

SELECT   idproduct_line, 
                            idprice_group,
                            currency_code, 
                            CASE 
                                     WHEN EXISTS 
                                              ( 
                                                     SELECT currency_code 
                                                     FROM   product_line_price_2 
                                                     WHERE  currency_code = 'GBP' 
                                                     AND    idproduct_line = product_line_price_2.idproduct_line AND !deleted) THEN Min(price)
                                     ELSE Min(price)*0.5098 
                            END AS userprice 
                   FROM     product_line_price_2 
                   WHERE    !deleted 
                   AND 
                            CASE 
                                     WHEN EXISTS 
                                              ( 
                                                     SELECT currency_code 
                                                     FROM   product_line_price_2 
                                                     WHERE  currency_code = 'GBP' 
                                                     AND    idproduct_line = product_line_price_2.idproduct_line AND !deleted) THEN currency_code = 'GBP'
                                     ELSE currency_code = 'AUD' 
                            END 
                   GROUP BY idproduct_line 
                   ORDER BY product_line_price_2.idproduct_line ASC

我的预期输出是3条记录,2条显示最低价格的英镑价格,另一条显示最低价格的澳元定价,转换为英镑(通过查询中的'* 0.5098')。

我看到的实际产量只有2条带有英镑定价的记录,因此它忽略了澳元的定价。

2 个答案:

答案 0 :(得分:0)

尽我所能了解并使用您现有的代码,您可以尝试:

SELECT * 
FROM
    product_line 
    LEFT JOIN (
        SELECT
            idproduct_line, 
            idprice_group, 
            CASE 
                WHEN EXISTS (
                    SELECT
                        currency_code 
                    FROM
                        product_line_price 
                    WHERE
                        currency_code = 'GBP' 
                        AND idproduct_line = product_line_price.idproduct_line
                ) THEN
                    MIN(price)
                ELSE
                    MIN(price) * 0.5098 
            END AS userprice
        FROM
            product_line_price 
        WHERE
            deleted = 0
            AND CASE WHEN EXISTS (
                SELECT
                    currency_code 
                FROM
                    product_line_price 
                WHERE
                    currency_code = 'GBP' 
                    AND idproduct_line = product_line_price.idproduct_line
            ) THEN
                currency_code = 'GBP'
                ELSE
                    currency_code = 'AUD' 
            END 
        GROUP BY
            idproduct_line 
        ORDER BY
            idproduct_line ASC
    ) AS product_line_price ON product_line.idproduct_line = product_line_price.idproduct_line 
WHERE
    product_line.deleted = 0
    AND product_line.idproduct_line_status = 1 
    AND product_line.idproduct_line IN (
        SELECT
            idproduct_line
        FROM
            product_line_has_product_category
        WHERE
            idproduct_category = '103'
    )
    AND product_line_price.idprice_group IN ( 
        SELECT idprice_group
        FROM price_group
        WHERE
            !deleted
            AND PUBLIC
            AND active
            AND userprice <= 250
    )
ORDER BY
    product_line.idproduct_line ASC;  

试试这个:

SELECT 
    pl.*,
    IF(plp.currency_code = 'GBP', MIN(IFNULL(plp.price, 0)), MIN(IFNULL(plp.price, 0)) * 0.5098)
FROM
    product_line pl
    LEFT JOIN product_line_price plp ON plp.idproduct_line = pl.idproduct_line
WHERE
    !pl.deleted
    AND !plp.deleted
    AND plp.currency_code IN ('GBP','AUD')
    AND pl.idproduct_line_status = 1 
    AND pl.idproduct_line IN (
        SELECT
            idproduct_line
        FROM
            product_line_has_product_category
        WHERE
            idproduct_category = '103'
    )
    AND plp.idprice_group IN ( 
        SELECT idprice_group
        FROM price_group
        WHERE
            !deleted
            AND public = 1
            AND active
            AND userprice <= 250
    )
ORDER BY
    pl.idproduct_line ASC;  

最后,请试试这个:

SELECT 
    pl.*,
    plp.idproduct_line,
    plp.idprice_group
    IF(plp.currency_code = 'GBP', MIN(IFNULL(plp.price, 0)), MIN(IFNULL(plp.price, 0)) * 0.5098)
FROM
    product_line pl
    LEFT JOIN product_line_price plp ON plp.idproduct_line = pl.idproduct_line
    LEFT JOIN product_line_has_product_category plhpc ON plhpc.idproduct_line = pl.idproduct_line
    LEFT JOIN price_group pg ON pg.idprice_group = plp.idprice_group
WHERE
    pl.deleted = 0
    AND pl.idproduct_line_status = 1
    AND plp.deleted = 0
    AND plp.currency_code IN ('GBP','AUD')
    AND plhpc.idproduct_category = '103'
    AND !pg.deleted
    AND pg.public
    AND pg.active
    AND pg.userprice <= 250
ORDER BY
    pl.idproduct_line ASC;  

答案 1 :(得分:0)

经过长时间的斗争和工作同事的帮助,我们采取了不同的方法,找到了解决这个问题的方法。

SELECT product_line.idproduct_line, 
       Min(local_price.price)    local_userprice, 
       Min(fallback_price.price) fallback_userprice 
FROM   product_line 
       INNER JOIN product_line_has_product_category 
               ON product_line.idproduct_line = 
                  product_line_has_product_category.idproduct_line 
                  AND 103 = product_line_has_product_category.idproduct_category 
       LEFT JOIN (product_line_price local_price 
                  INNER JOIN price_group local_price_group 
                          ON local_price.idprice_group = 
                             local_price_group.idprice_group 
                             AND ! local_price_group.deleted 
                             AND local_price_group.PUBLIC 
                             AND local_price_group.active) 
              ON product_line.idproduct_line = local_price.idproduct_line 
                 AND 'GBP' = local_price.currency_code 
       LEFT JOIN (product_line_price fallback_price 
                  INNER JOIN price_group fallback_price_group 
                          ON fallback_price.idprice_group = 
                             fallback_price_group.idprice_group 
                             AND ! fallback_price_group.deleted 
                             AND fallback_price_group.PUBLIC 
                             AND fallback_price_group.active) 
              ON product_line.idproduct_line = fallback_price.idproduct_line 
                 AND 'AUD' = fallback_price.currency_code 
WHERE ! product_line.deleted 
      AND product_line.idproduct_line_status = 1 
GROUP  BY product_line.idproduct_line 
HAVING ( local_userprice IS NULL 
         AND fallback_userprice <= 250 ) 
        OR ( local_userprice <= 250 ) 
ORDER  BY product_line.idproduct_line ASC 

使用连接,交叉引用GBP和AUD的值(这给同一行中的价格和货币提供了2列)..然后我们可以使用HAVING子句比较每列,结果是成功的! / p>