MySQL Filter结果再次出现

时间:2013-09-09 13:28:18

标签: mysql sql

这里的目标是: 1.从EACH商店获取具有最新日期的行以获取每种成分。 2.从这个结果中,比较价格,找到最便宜的商店。

我可以在单独的查询中完成第一个或第二个目标,但不能在同一个目标中完成。 如何过滤掉选择,然后对前一个结果应用另一个过滤器?

编辑: 我一直遇到从MAX和MIN得到的结果的问题,因为它只是随意取出其余的数据。为了避免这种情况,我应该在多列上连接表(我猜)。我不知道这对于重复的日期等是如何工作的。

我已经包含了查询及其输出数据的图像。

enter image description here

如果我们使用ingredient1作为例子,它存在于三个独立的商店中(在不同日期两次存储在一个商店中)。

在这种情况下,ingredient1的最便宜的当前价格将是store3。如果2013-05-25的第四排更便宜,由于它已经过时,它仍然不会“赢”。 (无视品牌名称,他们在这个问题上并不重要。)

非常感谢您提供的任何帮助/意见!

3 个答案:

答案 0 :(得分:1)

这可能需要将几个子查询连接在一起。

这未经过测试(因为我没有您的表格定义,也没有任何测试数据),但是这样的话: -

SELECT i.name AS ingredient,
        ip.price,
        ip.date,
        s.name AS storename,
        b.name AS brandname
FROM ingredient i
INNER JOIN ingredient_price ip
ON ingredient.ingredient_id = ingredient_price.ingredient_id
INNER JOIN store_to_ingredient_price stip
ON ingredient_price.ingredient_price_id = store_to_ingredient_price.ingredient_price_id
INNER JOIN store s 
ON store_to_ingredient_price.store_id = store.store_id
INNER JOIN brand_to_ingredient_price btip
ON ingredient_price.ingredient_price_id = brand_to_ingredient_price.ingredient_price_id
INNER JOIN brand b
ON brand_to_ingredient_price.brand_id = brand.brand_id  
INNER JOIN  
(
    SELECT i.ingredient_id,
            stip.store_id,
            ip.date,
            MIN(ip.price) AS lowest_price
    FROM ingredient i
    INNER JOIN ingredient_price ip
    ON ingredient.ingredient_id = ingredient_price.ingredient_id
    INNER JOIN store_to_ingredient_price stip
    ON ingredient_price.ingredient_price_id = store_to_ingredient_price.ingredient_price_id
    INNER JOIN
    (
        SELECT i.ingredient_id,
                stip.store_id,
                MAX(ip.date) AS latest_date
        FROM ingredient i
        INNER JOIN ingredient_price ip
        ON ingredient.ingredient_id = ingredient_price.ingredient_id
        INNER JOIN store_to_ingredient_price stip
        ON ingredient_price.ingredient_price_id = store_to_ingredient_price.ingredient_price_id
        GROUP BY ingredient_id, store_id
    ) Sub1
    ON i.ingredient_id = Sub1.ingredient_id
    AND stip.store_id = Sub1.store_id
    AND ip.date = Sub1.latest_date
    GROUP BY i.ingredient_id, stip.store_id, ip.date
) Sub2
ON  i.ingredient_id = Sub2.ingredient_id
AND stip.store_id = Sub2.store_id
AND ip.date = Sub2.date
AND ip.price = Sub2.lowest_price

答案 1 :(得分:1)

这个问题非常有趣!

因此,首先,我们从EACH商店获取每个成分的最新日期行。 (每个商店的最新日期可能会有所不同。) 然后,我们比较每个商店的价格(无论日期),以找出每种成分的最低价格。

下面的查询很好地使用了GROUP_CONCAT函数。这是关于函数使用的SO question

SELECT
   i.name as ingredient_name
  , MIN(store_price.price) as price
  , SUBSTRING_INDEX(
    GROUP_CONCAT(store_price.date ORDER BY store_price.price),
    ',',
    1
    ) as date
  , SUBSTRING_INDEX(
    GROUP_CONCAT(s.name ORDER BY store_price.price),
    ',',
    1
    ) as store_name
  , SUBSTRING_INDEX(
    GROUP_CONCAT(b.name ORDER BY store_price.price),
    ',',
    1
    ) as brand_name
FROM
  ingredient i
JOIN
(SELECT
  ip.ingredient_id as ingredient_id
  , stip.store_id as store_id
  , btip.brand_id as brand_id
  , CONVERT(SUBSTRING_INDEX(
    GROUP_CONCAT(ip.ingredient_price_id ORDER BY ip.date DESC),
    ',',
    1
    ), UNSIGNED INTEGER) as ingredient_price_id
  , MAX(ip.date) as date
  , CONVERT(SUBSTRING_INDEX(
    GROUP_CONCAT(ip.price ORDER BY ip.date DESC),
    ',',
    1
    ), DECIMAL(5,2)) as price
FROM ingredient_price ip
JOIN store_to_ingredient_price stip ON ip.ingredient_price_id = stip.ingredient_price_id
JOIN brand_to_ingredient_price btip ON ip.ingredient_price_id = btip.ingredient_price_id
GROUP BY 
  ip.ingredient_id
  , stip.store_id) store_price
ON i.ingredient_id = store_price.ingredient_id
JOIN store s ON s.store_id = store_price.store_id
JOIN brand b ON b.brand_id = store_price.brand_id
GROUP BY
  store_price.ingredient_id;

您可以查看此SQL Fiddle上的实施。

以下版本忽略了该品牌,但略小一些:

SELECT
   i.name as ingredient_name
  , MIN(store_price.price) as price
  , SUBSTRING_INDEX(
    GROUP_CONCAT(store_price.date ORDER BY store_price.price),
    ',',
    1
    ) as date
  , SUBSTRING_INDEX(
    GROUP_CONCAT(s.name ORDER BY store_price.price),
    ',',
    1
    ) as store_name
FROM
  ingredient i
JOIN
(SELECT
  ip.ingredient_id as ingredient_id
  , stip.store_id as store_id
  , CONVERT(SUBSTRING_INDEX(
    GROUP_CONCAT(ip.ingredient_price_id ORDER BY ip.date DESC),
    ',',
    1
    ), UNSIGNED INTEGER) as ingredient_price_id
  , MAX(ip.date) as date
  , CONVERT(SUBSTRING_INDEX(
    GROUP_CONCAT(ip.price ORDER BY ip.date DESC),
    ',',
    1
    ), DECIMAL(5,2)) as price
FROM ingredient_price ip
JOIN store_to_ingredient_price stip ON ip.ingredient_price_id = stip.ingredient_price_id
GROUP BY 
  ip.ingredient_id
  , stip.store_id) store_price
ON i.ingredient_id = store_price.ingredient_id
JOIN store s ON s.store_id = store_price.store_id
GROUP BY
  store_price.ingredient_id;

参考文献: Simulating First/Last aggregate functions in MySQL

答案 2 :(得分:0)

试试这个:

SELECT  `newest`.ingredient, `newest`.store,
        `newest`.brand, `newest`.price, `newest`.`latest_date`
FROM
        (SELECT         ingredient.name AS ingredient, store.name AS store,
                        brand.name AS brand, ingredient_price.price,
                        MAX( ingredient_price.date ) AS `latest_date`
        FROM            ingredient
        LEFT OUTER JOIN ingredient_price
            ON ingredient.ingredient_id = ingredient_price.ingredient_id
        LEFT OUTER JOIN store_to_ingredient_price
            ON ingredient_price.ingredient_price_id = store_to_ingredient_price.ingredient_price_id
        LEFT OUTER JOIN store
            ON store_to_ingredient_price.store_id = store.store_id
        LEFT OUTER JOIN brand_to_ingredient_price
            ON ingredient_price.ingredient_price_id = brand_to_ingredient_price.ingredient_price_id
        LEFT OUTER JOIN brand
            ON brand_to_ingredient_price.brand_id = brand.brand_id
        GROUP BY ingredient.name) `newest`

ORDER BY `newest`.price
LIMIT 1