【问题标题】:Another WHERE clause if there is no result如果没有结果,则另一个 WHERE 子句
【发布时间】:2013-04-24 13:56:42
【问题描述】:

在 mysql 的一个查询中执行此操作的最佳方法是什么?

SELECT * FROM products WHERE language = 1

如果没有结果

SELECT * FROM products WHERE language = 2 AND country = 1

如果没有结果

SELECT * FROM products WHERE language = 2 AND country = 2

【问题讨论】:

  • * 是哪些列?
  • 不幸的是,这不是 MySQL 中的一个查询:您希望从中得到什么
  • 我认为您可以使用 ORDER 获得所需的“逻辑”结果
  • 澄清这个问题,因为有一些答案建议将 WHERE 子句与 OR 分组:这不是 OP 想要的,他们只想得到来自 language = 1 的结果,或者只有来自language = 2 AND country = 1 的结果或仅来自language = 2 AND country = 2 的结果。
  • 您似乎已经使用存储过程来填充临时表或将“行集”对象传递给客户端。 stackoverflow.com/questions/4493932stackoverflow.com/questions/1629324

标签: mysql


【解决方案1】:

我已经对其进行了编辑以使其工作,但它不再优雅。


原件(没有最后一个且不存在)有缺陷。

事实证明这并不像我想象的那么聪明。请参见下面的 cmets。如果第一个和第三个查询返回数据,它将失败。如果您只有一个工会,而不是两个或更多工会,它确实有效。


在mysql中很简单:

select SQL_CALC_FOUND_ROWS * from products where language = 1
union
SELECT * FROM products WHERE language = 2 AND country = 1 and found_rows()=0
union
SELECT * FROM products WHERE language = 2 AND country = 2 and found_rows()=0 
AND not exists(select * from products where language = 1)

在此处查看有关 found_rows() 和 SQL_CALC_FOUND_ROWS 的讨论: http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_found-rows

【讨论】:

  • 你能在 UNION 语句中依赖 found_rows 吗?
  • @gbn 如果您没有在任何地方使用 LIMIT 并检查 0,则可以。
  • 嗯..我认为它实际上是可以挽救的.. 将其他 2 个语句包含在一个 select 中怎么样,那么它实际上是:1 个语句-Union-1 语句包含 2 个嵌套语句。
  • @meewoK 嵌套它们不起作用,您不能在子查询中放置另一个 SQL_CALC_FOUND_ROWS。
【解决方案2】:

您可以使用类似以下的内容:(编辑为使用基于 cmets 的 EXISTS 和 LIMIT)。

(
SELECT * FROM products WHERE language = 1
)
UNION
(
SELECT * FROM products WHERE language = 2 AND country = 1
AND NOT EXISTS(SELECT count(*) FROM products WHERE language = 1 limit 1)
)
UNION
(
SELECT * FROM products WHERE language = 2 AND country = 2 
AND NOT EXISTS(SELECT count(*) FROM products WHERE language = 2 AND country = 1 limit 1)
AND NOT EXISTS(SELECT count(*) FROM products WHERE language = 1 limit 1)
)

您使用嵌套查询和 count(*) 检查以前的查询是否为 NULL。

【讨论】:

  • 使用不存在可能比检查 0 计数更好。
  • @ShawnBalestracci 是否会在每一行重新执行这些子查询(COUNT 或 EXISTS - 无关紧要)?也许 left join + check for null 会更好?
  • 我有一种强烈的感觉,优化器计算了最佳分支并且只预先计算了一次。这就是 SQL 引擎这样做的原因:)。
  • @Shawn Balesstracci 谢谢,我会检查不存在并相应地更新我的答案。
【解决方案3】:

好像没有什么好办法,如果可能的话,你最好把它做成一个过程,要么填充临时表,要么将RowSet对象返回给客户端

但是,如果没有任何可能,您似乎限制了二级和三级查询:

SELECT * FROM products WHERE language = 1

UNION ALL

SELECT * FROM products WHERE language = 2 AND country = 1 
   AND NOT EXISTS (SELECT * FROM products WHERE language = 1)

UNION ALL

SELECT * FROM products WHERE language = 2 AND country = 2
   AND NOT EXISTS (SELECT * FROM products WHERE language = 1 OR (language = 2 AND country = 1 ))

但这一定是丑陋而缓慢的。

也许 LEFT JOIN with IS NULL 会比 NOT EXISTS 好

【讨论】:

    【解决方案4】:

    试试:

    select p.* 
    from (select min(language) minlang, min(country) minctry 
          from products where language = 1 or
                              (language = 2 and country in (1,2)) ) c
    join products p 
    on p.language = c.minlang and (c.minlang=1 or p.country=c.minctry)
    

    【讨论】:

      【解决方案5】:

      MySQL 缺少一次性实现此功能的功能
      示例:DENSE_RANK 窗口函数,或TOP..WITH TIES

      因此,不使用临时表或 IF 语句(无论如何都需要 MySQL 中的存储过程),然后在客户端将其过滤为最低优先级值。即消费行直到值改变

      SELECT *, 1 AS priority FROM products WHERE language = 1
      UNION ALL
      SELECT *, 2 AS priority FROM products WHERE language = 2 AND country = 1
      UNION ALL
      SELECT *, 3 AS priority FROM products WHERE language = 2 AND country = 2
      ORDER BY priority;
      

      这确实消除了到 MySQL 服务器的往返,即使不是很理想。而且它还避免了在 EXISTS 子句中重新评估以前的 SELECT

      【讨论】:

      • 如果您将优先级评估为案例条件,您可以在单个选择中执行此操作 - 类似于 case language when 1 then 1 when 2 then language + country else 4 end
      猜你喜欢
      • 1970-01-01
      • 2011-12-24
      • 1970-01-01
      • 2011-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多