对于具有n个有效价格的产品,请加入产品表和价格表

时间:2011-11-09 12:40:28

标签: mysql sql

我有以下产品和价格表:

表格:产品

productID   
---------
1
2
3
4
5

表格:价格

priceID     productID   started     expires
-------------------------------------------
1           1           2011-11-05  NULL    
2           1           2011-11-05  2011-11-20
3           2           2011-11-05  NULL
4           3           2011-11-05  NULL
5           3           2011-11-06  2011-11-08

我希望以这样一种方式加入他们:

  1. 每件产品只需一个价格
  2. 如果price.started <= NOW() AND ( price.expires >= NOW() || price.expires IS NULL )
  3. ,价格有效
  4. 如果一种产品有多个价格有效,则应选择价格较高的price.priceID
  5. 如果没有价格有效,仍会显示产品信息
  6. 这四个标准定义了有效价格的最有效(为了更好的条款)。因此对于NOW() == 2011-11-09,最终结果应为:

    priceID     productID   started     expires
    -------------------------------------------
    2           1           2011-11-05  2011-11-20
    3           2           2011-11-05  NULL
    4           3           2011-11-05  NULL
    

    我陷入了

    • 如果一种产品有多个价格有效,则应选择价格较高的price.priceID

    要求,这源于对一段时间内任何特定产品的多个有效价格的异乎寻常的业务要求。我的sql fu非常差,我走得很远:

    SELECT
        product.*,
        price.*
    FROM
        product
    LEFT JOIN
        price
    ON 
        price.productID = product.productID
        AND price.started <= NOW() 
        AND (
            price.expires IS NULL
            OR price.expires >= NOW()
        )
    

    NOW() == 2011-11-09当然导致:

    productID   priceID     productID   started     expires
    -------------------------------------------------------
    1           1           1           2011-11-05  NULL    
    1           2           1           2011-11-05  2011-11-20
    2           3           2           2011-11-05  NULL
    3           4           3           2011-11-05  NULL
    

    澄清(基于评论和答案):

    • 这些要求非常奇怪,但有效。重叠间隔是一个实际的业务需求,有时我需要显示所有价格(简单),有时只显示一个,更近期(我要问的)。
    • 无法更改数据模型。
    • 如果可能的话,我正在寻找整个联盟。 (或提示如何将子查询集成到最终连接中)
    • 我更喜欢基于标准SQL(ANSI / ISO)或MySQL的解决方案。

5 个答案:

答案 0 :(得分:3)

<强>更新

以下(完整)查询应该可以解决问题:

SELECT
    product.*,
    price.*
FROM
    product, 
   (SELECT price.* FROM price 
        WHERE price.started <= NOW() 
        AND 
            (price.expires IS NULL
            OR price.expires >= NOW())
    GROUP BY price.productId
    BY price.priceId DESC LIMIT 1) AS `price`
WHERE price.productID = product.productID;

答案 1 :(得分:1)

SELECT
    pro.*
  , pri.*
FROM 
    product AS pro
  JOIN
    price AS pri
      ON pri.priceID =
         ( SELECT p.priceID
           FROM price p 
           WHERE p.productID = pro.productID
             AND p.started <= CURRENT_DATE() 
             AND ( p.expires IS NULL
                OR p.expires >= CURRENT_DATE()
                 )
           ORDER BY p.priceId DESC 
           LIMIT 1
         )

答案 2 :(得分:0)

SELECT
    p.*,
  ( SELECT 
        TOP 1 pr.price 
    FROM price pr 
    WHERE pr.productID = p.productID 
      AND pr.started <= NOW() 
      AND (  pr.expires IS NULL 
          OR pr.expires >= NOW()) 
    ORDER BY 
        pr.productID DESC
  ) AS price
FROM product p

答案 3 :(得分:0)

如果要避免子查询,可以尝试以下语句:

SELECT
   product.*,
   price.*,
   MAX(price.priceID)
FROM
   product
LEFT JOIN
   price
ON 
   price.productID = product.productID
   AND price.started <= NOW() 
   AND (
      price.expires IS NULL
      OR price.expires >= NOW()
   )
GROUP BY price.productID

GROUP BY将仅使用max priceID强制结果中的不同产品。希望它有所帮助!

答案 4 :(得分:0)

WITH pc AS (
    SELECT pc1.priceid, pc1.productid
    , pc1.started, pc1.expires
    FROM tmp.price pc1
    WHERE pc1.started <= now()
    AND (pc1.expires IS NULL OR pc1.expires > now() )
    AND NOT EXISTS ( SELECT *
        FROM tmp.price pcx
        WHERE pcx.productid = pc1.productid
        AND pcx.started <= now()
            AND (pcx.expires IS NULL OR pcx.expires > now() )
        AND pcx.priceid > pc1.priceid
        )
    )
SELECT pd.productid
    , pd.productname
    , pc.started
    , pc.expires
FROM pc
JOIN tmp.product pd ON pc.productid = pd.productid
    ;

CTE是无名视图。如果您的DBMS不支持CTE,您可以将查询的第一个(CTE)部分放入命名视图中;子聚合物是相同的。因人而异。