【问题标题】:More concise SQL query involving MAX()涉及 MAX() 的更简洁的 SQL 查询
【发布时间】:2013-03-13 11:16:08
【问题描述】:
存货 +------------------+------------------+---------- --+ |影碟 |更换价格 |库存| +------------------+------------------+---------- --+ |圆周率 | 9.99 | 500 | |沙丘 | 29.99 | 100 | |希瑟斯 | 4.99 | 20 | |大白鲨 | 19.99 | 500 | | Mulholland_Drive | 39.99 | 50 | |醒来_生活 | 29.99 | 200 | +------------------+------------------+---------- --+ 租用 +-----------------+------------+------------------+ |订户 | queue_nbr |影碟 | +-----------------+------------+------------------+ |鲍勃 | 1 | Mulholland_Drive | |鲍勃 | 2 |大白鲨 | |蔡 | 1 |圆周率 | |蔡 | 2 |希瑟斯 | |杰米 | 2 | Mulholland_Drive | |杰米 | 4 |沙丘 | |杰米 | 1 |大白鲨 | |杰米 | 3 |醒来_生活 | |诺拉 | 4 |大白鲨 | |诺拉 | 2 | Mulholland_Drive | |诺拉 | 3 |沙丘 | |诺拉 | 1 |醒来_生活 | +-----------------+------------+------------------+

我只想返回拥有最昂贵电影队列的订阅者(想想如果您在给定时间丢失了所有电影,则需要 Netflix DVD 更换费用)。我使用了 MAX() 而不是 TOP、LIMIT 或 ROWNUM,因为查询需要尽可能独立于数据库,并且在出现平局时必须返回多个订阅者。使用上面的表格,结果应该是

+----------+ |最高 | +----------+ |杰米 | |诺拉 | +----------+

经过大量搜索和实验,我想出了可以工作的代码,但在我的新手眼中,无论是在代码数量上还是在执行上,都显得臃肿且效率低下。

有人介意重构和解释您的代码吗?

我的代码:


SELECT z.subscriber highest
FROM 
(SELECT MAX(price) max_price
    FROM (
        SELECT subscriber_name subscriber, SUM(replacement_price) price
        FROM inventory i
        INNER JOIN rented r
        ON i.DVD = r.DVD
        GROUP BY subscriber
    ) x
) y
INNER JOIN
(
    SELECT subscriber_name subscriber, SUM(replacement_price) price
    FROM inventory i
    INNER JOIN rented r
    ON i.DVD = r.DVD
    GROUP BY subscriber
) z
ON z.price = y.max_price

【问题讨论】:

  • 请通过添加适当的标签(Oracle、SQL Server、MySQL 等)指定您的目标关系数据库管理系统。可能有一些答案利用了不受普遍支持的语言或产品功能。此外,通过使用特定的 RDBMS 对其进行标记,您的问题可能会受到更适合回答的人的关注。
  • 如果可能的话,我希望查询可以在 MySQL 和 SQL-Server 上运行。

标签: mysql sql sql-server subquery max


【解决方案1】:

如果您只想返回总数为 max 的那些,那么您可以使用在 MySQL 和 SQL Server 中都可以使用的以下内容。不过,它并不比您当前的查询更简洁:

select subscriber
from inventory i
inner join rented r
  on i.dvd = r.dvd
group by subscriber
having sum(replacement_price) = (select max(TotalCost)
                                 from 
                                 (
                                   select sum(replacement_price) TotalCost
                                   from inventory i
                                   inner join rented r
                                     on i.dvd = r.dvd
                                   group by subscriber
                                  ) p);

如果您使用的是 SQL Server,那么我建议您实现窗口函数,类似于:

select subscriber
from
(
  select subscriber,
    rank() over(order by sum(replacement_price) desc) rnk
  from inventory i
  inner join rented r
    on i.dvd = r.dvd
  group by subscriber
) src
where rnk = 1

SQL Fiddle with Demo

【讨论】:

  • 谢谢。我被要求提早上班,但我会尽快检查您的代码。
  • 感谢您的详尽回复。我只用了几天的 SQL,而且只在我的 MBP 上预装了 MySQL 5.5;看到我已经解决的问题的替代解决方案很有帮助——尤其是当它们是由真正知道自己在做什么的人编写的时候。你的 MySQL 查询可能不会更简洁,但它比我的更具可读性,而且 SQL Server 查询非常干净。还要感谢 Fiddle 链接——我还没有找到像这样的暂存器来让我玩不同的 RDBMS。感谢您抽出宝贵时间。
【解决方案2】:
SELECT z.subscriber
FROM(
    SELECT RANK() OVER(ORDER BY SUM(replacement_price)) subscriber_rank, 
           r.subscriber subscriber, 
           SUM(replacement_price) totalReplacementPrice
    FROM inventory i
    INNER JOIN rented r ON i.dvd = r.DVD
GROUP BY subscriber
) z
WHERE z.subscriber_rank = 1

您从 sql 示例查询的某些列名不同,因此我使用了演示表中给出的列名。我在内部查询中使用 rank 函数通过replacement_price 的总和来查找所有订购人的顺序。然后选择排名为 1 的行。

Rank 在 MS Sql Server 和 Oracle 中都可用。要比@bluefeet 所说的更进一步,您需要提供更多关于您所针对的数据库的详细信息。

【讨论】:

  • 我已经修复了列名;对此感到抱歉。
  • 非常感谢您的帮助。不幸的是,我被叫走了,所以今天晚些时候我得试试你的问题。
  • 我是个菜鸟,当您写“[r]ank 在 MS SQL Server 和 Oracle 中都可用”时,我以为您将 MySQL 称为“Oracle”。当搜索 MySQL RANK() 函数为空时,我花了一分钟才意识到我的错误。我不想将自己局限于 MySQL,所以看看它在 SQL Server 中是如何完成的仍然很有帮助。在将您的查询粘贴到 sqlfiddle(直到 bluefeet 在他的回复中提到它时我才知道它存在)之后,我确实注意到 ORDER BY 子句需要 DESC 关键字来获取顶部而不是底部的订阅者。
猜你喜欢
  • 2016-07-26
  • 2021-06-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-26
相关资源
最近更新 更多