在子查询中引用外部查询

Posted

技术标签:

【中文标题】在子查询中引用外部查询【英文标题】:Referencing outer query in subquery 【发布时间】:2012-11-09 11:55:33 【问题描述】:

我有以下查询,该查询通常有效,并且应该返回涵盖定义时间范围的所有行(如果没有绝对匹配,则取最接近的前一行和下一行 - 概述于 http://www.orafaq.com/node/1834)

SELECT * FROM table
  WHERE id=__ID__ AND `date` BETWEEN 
    IFNULL((SELECT MAX(`date`) FROM table WHERE id=__ID__ AND `date`<=__LOWERLIMIT__), 0)
  AND
    IFNULL((SELECT MIN(`date`) FROM table WHERE id=__ID__ AND `date`>=__UPPERLIMIT__), UNIX_TIMESTAMP())
ORDER BY `date`

但希望通过引用外部选择来减少两个表子选择,但显然它不喜欢它

SELECT * FROM (SELECT * FROM table WHERE id=__ID__) b
  WHERE `date` BETWEEN 
    IFNULL((SELECT MAX(`date`) FROM b WHERE `date`<=__LOWERLIMIT__), 0)
  AND
    IFNULL((SELECT MIN(`date`) FROM b WHERE `date`>=__UPPERLIMIT__), UNIX_TIMESTAMP())
ORDER BY `date`

有没有办法在不选择三个表的情况下进行查询?

【问题讨论】:

【参考方案1】:

你可以通过加入来做这样的事情:

select * from table a
    inner join (
       select id,
              max(
                  if(`date` <= __LOWERLIMIT__ ,`date`, 0)
              ) as min_date,              
              min(
                 if(`date` >= __UPPERLIMIT__ , `date`, UNIX_TIMESTAMP())
              ) as max_date
           from table
           where id = __ID__
           group by id
    ) range on
    range.id = a.id and
    a.`date` between min_date and max_date;

我不是 mysql 专家,如果需要进行一些语法调整,敬请见谅。

更新: OP 还发现了this very nice solution。

【讨论】:

谢谢丹。主要我担心三个选择的性能(表会变得相当大,否则不会有那么大的问题),但本示例还涉及一个额外的联合子选择,并且没有实际测量它我会担心它可能有类似的潜在性能问题。您是否有特别的理由在最初的查询中提出建议?谢谢一百万 @user1841321,我相信如果给定 ID 有 1000 行,那么在原始 ID 中,max 和 min 的子查询将重复 1000 次。使用此连接解决方​​案,max 和 min 的计算只发生一次。 你相信它会因为外部查询而被调用 1000 次吗?它不会在这里做同样的事情吗(第二个选择是连接的子选择)? RANGE ON 似乎也不是 mysql 特定的,它的目的是什么? @user1841321,“范围”不是命令;它只是我给要加入的子选择的名称——类似于第一个表被称为“a”。 在连接发生之前,连接中的子查询总是会被处理一次,而WHERE 子句中的子查询会为每一行处理。原因是WHERE 子句中的子查询可能取决于特定行所考虑的特定内容。

以上是关于在子查询中引用外部查询的主要内容,如果未能解决你的问题,请参考以下文章

为啥 SQL 子查询中的外部引用会产生不同的结果?

SQL - 子查询和外部表之间的关系

如何在子查询中使用外部查询中的列从另一个表中获取结果?

如何定义在子查询中引用通配符表的 BQ 视图?

在 T-SQL 中,如何在子查询中引用表变量?

MySQL的SQL语句 - 数据操作语句(13)- 子查询