【问题标题】:SQL query simplificationSQL查询简化
【发布时间】:2012-07-06 13:36:36
【问题描述】:
select model from (
    select price, model from pc where price = (select max(price) from pc)
    union
    select price, model from laptop where price = (select max(price) from laptop)
    union
    select price, model from printer where price = (select max(price) from printer)
) t1 where price = (select max(price) from (
    select price, model from pc where price = (select max(price) from pc)
    union
    select price, model from laptop where price = (select max(price) from laptop)
    union
    select price, model from printer where price = (select max(price) from printer)
) t2 )

我对 SQL 很陌生,所以我的问题很简单,但我想理清一点。我对这个查询不能简化为这样的事情是对的吗?

select model from (
    select price, model from pc where price = (select max(price) from pc)
    union
    select price, model from laptop where price = (select max(price) from laptop)
    union
    select price, model from printer where price = (select max(price) from printer)
) t1 where price = (select max(price) from t1)

如果不能,我们运行两个相同的子查询是不是一件坏事?

【问题讨论】:

  • 仅通过查看查询很难理解表结构以及您要实现什么。?
  • 我们有 pc、笔记本电脑和打印机表,每个表有两列:型号和价格。目标是从所有表中找到最昂贵的模型。 MySQL。
  • @Kremchik - 改变你的结构。一张表,包含三列 (type, model, price),其中 type 包含 ids 对应的 {PC, Laptop, Printer}。然后,如果您添加例如monitor 或其他类型,则无需添加新表并更新所有查询。
  • @Dems,我可以重构我的架构,但问题是我们可以给查询结果一个名称并从中选择吗?第一个查询中t2 的意义何在?
  • @Kremchik - 许多 RDBMS 现在实现了公用表表达式。这些允许您定义一次子查询并在同一个外部查询中多次重复使用它。然而,MySQL 没有这种能力。就Why do I need the T2 alias? 而言,这仅仅是因为必须始终命名all 数据集。从技术上讲,你有SELECT MAX(t2.price),但你只是没有输入它。

标签: sql simplify simplification


【解决方案1】:

我仍然说要使用一张桌子,这是最佳实践设计。 (不要不必要地复制相同的表。)

CREATE TABLE unified_table (
  product_type,
  price,
  model
)

这样做会启用此查询...

SELECT
  *
FROM
  unified_table
WHERE
  price = (SELECT MAX(price) FROM unified_table)

但是,如果您不能或不愿相信优化器来处理 UNION 的后果...

SELECT
  *
FROM
(
  SELECT * FROM pc
  UNION ALL
  SELECT * FROM laptop
  UNION ALL
  SELECT * FROM printer
) t1
WHERE
  price = (SELECT MAX(price) FROM (SELECT price FROM pc
                                   UNION ALL
                                   SELECT price FROM laptop
                                   UNION ALL
                                   SELECT price FROM printer
                                  ) t2
          )

优化器将了解如何对其进行优化以消除冗余搜索。


编辑:

作为一种折衷方案,您可以做出统一的视图,并查询...

CREATE VIEW unified_table AS
  SELECT 'pc'      AS type, * FROM pc
  UNION ALL
  SELECT 'laptop'  AS type, * FROM laptop
  UNION ALL
  SELECT 'printer' AS type, * FROM printer

【讨论】:

  • 好的,所以我想这不是因为优化器而在最后一个代码示例中重复查询的问题吗?
  • @Kremchik - T1T2 将分别创建和处理。但是您不需要T2 中执行三个MAX(),优化器已经知道如何执行三个UNIONed 表的MAX()。并且您不需要对T1 中的每个表进行预过滤,优化器只需使用T2 中的MAX() 的结果对每个表进行一次搜索。
【解决方案2】:

试试这样的:

select model, price
from (
    select price, model from pc order by price desc limit 1
    union
    select price, model from laptop order by price desc limit 1
    union
    select price, model from printer order by price desc limit 1
) t1 
order by price desc
limit 1

但是我建议您检查您的数据库结构,这似乎是您根据类型为相同的东西(项目)创建了多个表。您可以将所有这些保存在一个表中,仅通过类型列的内容来区分。

无限制:

select t1.model, t1.price
from 
(select max(price) p
 from
    select max(price) p from pc
    union
    select max(price) p from laptop
    union
    select max(price) p from printer
) max_price
JOIN (
    select price, model from pc
    union
    select price, model from laptop
    union
    select price, model from printer
) t1 ON price >= max_price.p

【讨论】:

  • 谢谢!但我不认为我可以使用limit 1 声明,因为可以存在两个或多个具有相同价格的模型,这是最高价格。
  • @Kremchik:这真的重要吗?
  • 是的,因为可以有:pc: {100, $1000}printer: {105, $2000}laptop: {110, $2000}。查询结果应为 105 和 110。
  • 我知道它可能会发生,问题是它真的很重要吗?无论如何,我也提供了无限的解决方案。正如 Dems 所说,最好换个桌子。
  • 是的,我知道了。谢谢你,马兹!
【解决方案3】:
select * from (
    select price, model from pc where price = (select max(price) from pc)
    union
    select price, model from laptop where price = (select max(price) from laptop)
    union
    select price, model from printer where price = (select max(price) from printer)
) order by Price desc limit 1

因为你有 3 个值要比较,来自不同的表,没有关系,你必须做一个联合,然后比较它们

这是一种方式,你不需要重新计算价格。

【讨论】:

  • 我们不能使用limit,因为可以有两个或多个相同价格的模型,这是最高的价格。但无论如何我的问题是:我们可以无论如何命名查询结果并从中选择吗?
猜你喜欢
  • 2021-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-12
  • 2010-09-29
  • 2010-12-31
  • 1970-01-01
相关资源
最近更新 更多