短路逻辑评估运算符

Posted

技术标签:

【中文标题】短路逻辑评估运算符【英文标题】:Short-circuit logic evaluation operators 【发布时间】:2013-06-02 21:58:06 【问题描述】:

是否有任何短路逻辑运算符(特别是短路AND 和短路OR)可以在 mysql 5.5 的WHERE 子句中使用?如果没有,有什么替代方案?

我的问题的抽象观点以及我为什么需要这个的解释可以在这个小提琴中找到:

http://sqlfiddle.com/#!2/97fd1/3

实际上,我们正在数百个国家/地区的数千个城市的数百万家书店中查看数百万本书,这就是为什么我们不能接受每次发送查询时接收不需要的信息的开销,并且迫切需要找到一种方法在我们获得所有满足当前条件的行后立即停止评估,然后继续进行下一个 OR。

如果您需要更多信息,请告诉我。提前致谢。


根据要求,这里是小提琴中使用的架构:

CREATE TABLE quantitycache (
  id INT AUTO_INCREMENT,
  quantity INT,
  book_id INT NOT NULL,
  bookstore_id INT NULL,
  city_id INT NULL,
  country_id INT NULL,
  PRIMARY KEY (id)
);

以及一些示例数据:

INSERT INTO quantitycache 
     (quantity, book_id, bookstore_id, city_id, country_id)
VALUES
     (5,        1,       1,            NULL,    NULL),
     (100,      2,       1,            NULL,    NULL),
     (7,        1,       2,            NULL,    NULL),
     (12,       1,       NULL,         1,       NULL),
     (12,       1,       NULL,         NULL,    1),
     (100,      2,       NULL,         1,       NULL),
     (100,      2,       NULL,         NULL,    1),
     (200,      3,       NULL,         1,       NULL),
     (250,      3,       NULL,         NULL,    1);

【问题讨论】:

我认为唯一能做到这一点的方法是使用 T-SQL。如果您编写查询所有存储的查询,那么您将等待很长时间,但是使用 T-SQL 您可以设置变量和标志等以跳出迭代执行一小部分查询的循环(即逐个存储查询)一旦找到匹配项。 我敢打赌,只要其中一种情况匹配,它就会停止评估 OR 表达式,只要表达式没有副作用。 @Barmar:不幸的是,这不是真的,正如您在小提琴中看到的那样,满足其他 OR 条件的行也会返回。 这就是OR 的意思——返回满足任何条件的行。 确实如此,这就是为什么我要问是否有办法使用短路逻辑运算符而不是急切运算符。 【参考方案1】:

请记住,查询不会强制执行。您编写的查询可能在多个线程上运行,因此 where 子句中的短路运算符不会只产生一个结果。

改为使用LIMIT 子句仅返回第一行。

SELECT * FROM quantitycache
WHERE bookstore_id = 1 OR city_id = 1 OR country_id = 1
ORDER BY bookstore_id IS NULL ASC,
         city_id IS NULL ASC,
         country_id IS NULL ASC
LIMIT 1;

要获得结果集中所有书籍的最佳匹配,请将结果保存到临时表,找到最佳结果,然后返回感兴趣的字段。

CREATE TEMPORARY TABLE results (id int, book_id int, match_rank int);

INSERT INTO results (id, book_id, match_rank)
SELECT id, book_id, 
    -- this assumes that lower numbers are better
    CASE WHEN Bookstore_ID is not null then 1 
         WHEN City_ID is not null then 2 
         ELSE 3 END as match_rank
FROM quantitycache
WHERE bookstore_id = 1 OR city_id = 1 OR country_id = 1;

Select * 
from (
    select book_id, MIN(match_rank) as best_rank 
    from results 
    group by book_id
) as r
inner join results as rid 
    on r.book_id = rid.book_id 
    and rid.match_rank = r.best_rank
inner join quantitycache as q on q.id = rid.id;

DROP TABLE results;

【讨论】:

感谢您的回答,不幸的是,这只会返回一个 book_id,而我们实际上需要获取所有书籍的结果。 ... 错误,但您的问题指出“一旦我们一击中就停止”。如果您需要获得所有结果,那么您将不得不遍历所有行@ChristianKiewiet 我认为他的意思是“一旦满意就停止检查OR 中的列”。 让我将其改写为“一旦我们拥有满足当前条件的所有行” 在检查所有行之前,您无法知道您是否拥有所有满足的行。

以上是关于短路逻辑评估运算符的主要内容,如果未能解决你的问题,请参考以下文章

c中的内部短路评估

短路评估顺序和前缀增量运算符

看过来,这里有JavaScript技术干货?

使用三元运算符或仅短路评估之间的区别?

if-then-else 运算符的短路评估(例如 ?: 在 C 中)

当运算符优先级说不应该时,为啥短路评估会起作用?