【问题标题】:MySQL: Getting the MIN and the MAX of a table and both of their titlesMySQL:获取表的 MIN 和 MAX 以及它们的标题
【发布时间】:2015-04-14 19:21:41
【问题描述】:

我有一个庞大的产品数据库。它与另一个价格表有一对多的关系。我可以通过一次查询轻松获得特定类别的 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 

min2.99prod6,因为prod12.99 价格已过期。

max89.99prod7,因为 99.99 的价格 prod7 已过期。

ave25.85,因为上面的原因,因为prod5 的价格是24.99

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

【问题讨论】:

  • 你打算怎么处理领带?
  • 可能有多个产品与minmax 相关联 - 但是,由于这是一份概览报告,因此只需要一个名称。它只需要是我遇到问题的正确的。
  • 价格日期是日期列吗?
  • 现在是日期时间。因此,price_id 最大或 price_date 最高的产品应该给出最新价格。

标签: mysql inner-join min


【解决方案1】:

要解决您的第一个输出,只需使用 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

我不明白你的第二个输出的规则。

【讨论】:

  • 如果价格不是唯一的,这会造成混乱。
  • @shawnt00 - 没有混乱...超过一排。这是意料之中的,您有多个结果。
  • 当您有 2 个最低价格的产品和 3 个最高价格的产品时,您将获得总共 6 行以及它们之间的所有对。
  • 他想在第二个输出中排除过期的价格,我相信。
  • 忘记我想忘记过期价格的事实,一旦我使用 GROUP BY 这个作品。如果没有 GROUP BY,我会得到相同的重复结果。所以我很高兴地说明第一轮(我的问题以粗体表示)有效! (我的披萨已经做好了,很快就会回来)
【解决方案2】:

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

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 中使用限制和排序方法进行操作的 hack:

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

【讨论】:

  • 哇!这就是为什么这个网站很棒。您刚刚向我展示了一个我不知道存在也不知道如何使用它的功能。 with 语句可能已经破解了它,上面看起来很可能会成功。我将测试以上所有内容(现在有几个要完成),看看哪一个得到最好的结果(并做我的晚餐)。真是太感谢你了!!
  • 有一个你不知道的原因。 mysql 不支持withstackoverflow.com/questions/324935/mysql-with-clause
  • 我不确定 mysql 是否支持。
  • @shawnt00 - row_number() 也不是 - 两者都会让这个问题更容易回答。
  • 您无疑花了很长时间才想出这个解决方案,但是,我不断收到错误,而且嵌套的子查询太多,我发现很难知道错误在哪里。我还怀疑这个查询需要很长时间才能运行,因此,即使它可以工作,运行所需的时间可能意味着我只需要想一个更简单的方法,然后做一个全新的 AJAX 查询来找出这些其他的东西吗?
【解决方案3】:
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)

【讨论】:

  • 这是回复中的一个,我先测试了。这一切对我来说似乎更容易理解,但是在将上述内容与我的大数据库集成后,我得到了相当虚假的结果。需要注意的是,上面有一些拼写错误(minprice 表中有 MAX,最后一个内部连接我将 s.id = max... 更改为 s2.id = max... 等),但是你的意思是什么被理解了,我也相应地改变了。所以,坏消息是,不适合我,但我会尝试扩展它。谢谢。
  • 是的,对不起,我错过了到期日期部分,所以我得到了价格的最大 prod_id,所以 minprice 表中的 MAX 本来是这样......顺便说一句,价格日期是一个日期柱子?如果是这样,t1 子查询可以更智能
  • 是的,price_date 是日期时间。我想有两种方法来处理它......要么id较大的是最新价格,要么日期较大的是新价格。
  • 我加了NOT EXISTS,请试试
猜你喜欢
  • 2020-06-18
  • 1970-01-01
  • 2017-06-10
  • 1970-01-01
  • 2020-08-22
  • 1970-01-01
  • 2016-08-27
  • 2012-02-17
  • 1970-01-01
相关资源
最近更新 更多