MySQL:获取表格及其两个标题的MIN和MAX

时间:2015-02-13 17:06:02

标签: mysql inner-join min

我有一个庞大的产品数据库。它与另一个价格表有一对多的关系。通过一个查询,我可以很容易地得到特定类别的MIN,MAX和AVG。

SELECT 
  MIN(gbp.price) AS min,
  ROUND(AVG(gbp.price),2) AS ave,
  MAX(gbp.price) AS max
FROM sku AS s
  INNER JOIN price gbp ON gbp.sid = s.id

但是,我也希望能够获得与之相关的产品的标题 - 尽管进行了多次搜索和重写,我仍然无法解决这个问题。

我的数据类似于......

prod_id | title
===============
1       | prod1
2       | prod2
3       | prod3
4       | prod4
5       | prod5
6       | prod6
7       | prod7

price_id | prod_id | price | price_date
=======================================
1        | 1       | 2.99  | 2015/02/01
2        | 1       | 3.99  | 2015/02/12
3        | 2       | 12.99 | 2015/02/01
4        | 3       | 15.99 | 2015/02/01
5        | 4       | 29.99 | 2015/02/01
6        | 5       | 29.99 | 2015/02/01
7        | 5       | 24.99 | 2015/02/12
8        | 6       | 2.99  | 2015/02/01
9        | 7       | 99.99 | 2015/02/01
10       | 7       | 89.99 | 2015/02/12

我会假设其他人可能想要一个与此类似的查询,所以我要求两个答案。

第一个"简单地"要归还......

min  | min_title | ave   | max   | max_title
============================================
2.99 | prod1     | 31.39 | 99.99 | prod7 

但是,我想要的真正答案(尽管事实上我甚至无法解决上述问题)都会变得更加棘手。

我想要的实际结果如下表所示......

min  | min_title | ave   | max   | max_title
============================================
2.99 | prod6     | 25.85 | 89.99 | prod7 

min 2.99 prod6 2.99prod1 max价已过期。

89.99 prod7 99.99 prod7ave 25.85价已过期。

prod5因为上述而24.99,因为{{1}}的价格为{{1}}。

我不期待一切的答案,只是回答第一个问题(粗体)可能会引导我找到第二部分的答案(因为我有类似的查询得到最新的价格等)。

3 个答案:

答案 0 :(得分:0)

要解决您的第一个输出,只需使用join来获取这些值:

SELECT min, mint.title, ave, max, maxt.title
FROM (
    SELECT 
      MIN(gbp.price) AS min,
      ROUND(AVG(gbp.price),2) AS ave,
      MAX(gbp.price) AS max
    FROM (SELECT price 
          FROM price AS gbp 
          INNER JOIN sku s2 ON gbp.sid = s2.id 
          ORDER BY prdate DESC 
          LIMIT 0, 1) AS s
    INNER JOIN price gbp ON gbp.sid = s.id
) inq
JOIN price minp ON inq.min = minp.price
JOIN price maxp on inq.max = maxp.price
JOIN prod mint ON minp.prod_id = mint.prod_id
JOIN prod maxt ON maxp.prod_id = maxt.prod_id

我不理解第二次输出的规则。

答案 1 :(得分:0)

这实际上是两个不同的查询(如果计算平均值,则为三个查询)。交叉连接只是将最小值和最大值的两个结果水平拼接在一起。它们显然可以分开并单独执行。

with current_prices as (
    select price_id, prod_id, price
    from prices
    where price_date = (
        select max(price_date)
        from prices as prices2
        where prices2.prod_id = prices.prod_id
    )
),
min_current_prices as (
    select price, min(prod_id) as prod_d /* arbitrary selected representative */
    from current_prices
    where price = (
        select min(price)
        from current_prices
    )
    group by price
),
max_current_prices as (
    select price, min(prod_id) as prod_id /* arbitrary selected representative */
    from current_prices
    where price = (
        select max(price)
        from current_prices
    )
    group by price
)
select
    m1.price, prod1.title,
    (select avg(price) from current_prices) as ave,
    m2.price, prod2.title
from
    min_current_prices as m1 inner join products as prod1 on prod1.prod_id = m1.prod_id
    max_current_prices as m2 inner join products as prod2 on prod2.prod_id = m2.prod_id

我觉得这看起来太复杂了,但你却要求一些非常不寻常的东西。显然可能会有相同的最低/最高价格的产品,因此当两端都有多个产品时会出现问题。

如果您的平台不支持WITH,则只需替换完整查询:

select
    min_current_price.price as min_price, min_prod.title as min_title,
    (
        select avg(price)
        from prices
        where price_date = (
            select max(price_date)
            from prices as prices2
            where prices2.prod_id = prices.prod_id
        )
    ) as ave,
    max_current_price.price as max_price, max_prod.title as max_title
from
(
    select price, min(prod_id) as prod_id /* arbitrarily selected representative */
    from (
        select *
        from prices
        where price_date = (
            select max(price_date)
            from prices as prices2
            where prices2.prod_id = prices.prod_id
            )
        ) as current_prices
    where price = (
        select min(price)
        from prices
        where price_date = (
            select max(price_date)
            from prices as prices2
            where prices2.prod_id = prices.prod_id
            )
        )
    group by price
) as min_current_price

cross join

(
    select price, min(prod_id) as prod_id /* arbitrarily selected representative */
    from (
        select *
        from prices
        where price_date = (
            select max(price_date)
            from prices as prices2
            where prices2.prod_id = prices.prod_id
            )
        ) as current_prices
    where price = (
        select max(price)
        from prices
        where price_date = (
            select max(price_date)
            from prices as prices2
            where prices2.prod_id = prices.prod_id
            )
        )
    group by price
) as max_current_price

inner join products as min_prod on min_prod.prod_id = min_current_price.prod_id
inner join products as max_prod on max_prod.prod_id = max_current_price.

这是使用限制和排序方法在mysql中进行的黑客攻击:

select
    minprice.price as min_price, minprod.title as min_title,
    (
        select avg(price)
        from prices
        where price_date = (
            select max(price_date)
            from prices as prices2
            where prices2.prod_id = prices.prod_id
        )
    ) as ave,
    maxprice.price as max_price, maxprod.title as max_title
from
(
    select price_id, price, prod_id
    from prices
    where not exists ( /* another way of excluding expired prices */
        select 1 from prices as p2
        where p2.prod_id = prices.prod_id and p2.price_date > prices.prod_id
    )
    order by price asc
    limit 0, 1
) as minprice,

(
    select price_id, price, prod_id
    from prices
    where not exists (
        select 1 from prices as p2
        where p2.prod_id = prices.prod_id and p2.price_date > prices.prod_id
    )
    order by price desc
    limit 0, 1
) as maxprice

inner join prod as minprod on minprod.prod_id = minprice.prod_id
inner join prod as maxprod on min.prod_id = maxprice.prod_id

答案 2 :(得分:0)

SELECT t1.min, s.title AS min_title, t1.ave, t1.max, s2.title AS max_title
FROM (SELECT 
        MIN(gbp.price) AS min,
        ROUND(AVG(gbp.price),2) AS ave,
        MAX(gbp.price) AS max
    FROM sku AS s
        INNER JOIN price gbp ON (gbp.sid = s.id)
) t1
  INNER JOIN (SELECT gbp.price, MAX(gbp.prod_id) AS MaxProdID
    FROM price gbp
    WHERE NOT EXISTS(
        SELECT p2.price_id 
        FROM price p2 
        WHERE p2.price_id > gbp.price_id 
        AND p2.prod_id = gpb.prod_id
    )
    GROUP BY gbp.price
  ) minprice ON (minprice.price = t1.min)
  INNER JOIN sku s ON (s.id = minprice.MaxProdID)
  INNER JOIN (SELECT gbp.price, MAX(gbp.prod_id) AS MaxProdID
    FROM price gbp
    WHERE NOT EXISTS(
        SELECT p2.price_id 
        FROM price p2 
        WHERE p2.price_id > gbp.price_id 
        AND p2.prod_id = gpb.prod_id
    )
    GROUP BY gbp.price
  ) maxprice ON (maxprice.price = t1.max)
  INNER JOIN sku s2 ON (s2.id = maxprice.MaxProdID)