首页 > 解决方案 > 在 SQL 查询中的 WHERE 语句中具有条件

问题描述

我有两个查询返回相同的列集。

SELECT A.FIRST_NAME, A.MIDDLE_NAME, A.Age, B.Address
FROM table1 A INNER JOIN table2 B on A.ID = B.ID 
WHERE A.FIRST_NAME IN ('123')

SELECT A.FIRST_NAME, A.MIDDLE_NAME, A.Age, B.Address
FROM table1 A INNER JOIN table2 B on A.ID = B.ID
WHERE B.Address IN ('123')

如果用户输入 first_name 作为输入,则必须选择第一个查询的结果,如果用户输入 Address 作为输入,则必须选择第二个查询的结果。

当用户给出名字时,我尝试使用 (A.FIRST_NAME = '123' or B.Address = ''),当用户给出中间名时,我尝试使用 (A.FIRST_NAME = '' or B.Address = '123') 但是它使查询永远运行。

SELECT A.FIRST_NAME, A.MIDDLE_NAME, A.Age, B.Address
FROM table1 A INNER JOIN table2 B on A.ID = B.ID
WHERE A.FIRST_NAME IN ('') OR B.Address IN ('123')

我想听听我的同行专家的建议。

标签: mysqlsqldatabase

解决方案


典型的方法是这样的:

SELECT a.first_name, a.middle_name, a.age, b.address
FROM table1 a
INNER JOIN table2 b on a.id = b.id 
WHERE (a.first_name = @first_name OR @first_name IS NULL)
  AND (a.address = @address OR @address IS NULL);

这适用于

  • 只给出名字
  • 只给出地址
  • 两者都给出(在这种情况下,只返回匹配两个条件的行)
  • 没有给出(在这种情况下,所有行都被返回)

DBMS 必须找到适用于所有条件的执行计划。这可能是不一定很慢的全表扫描,但这也不会很快。

这与UNION查询不同:

SELECT a.first_name, a.middle_name, a.age, b.address
FROM table1 a
INNER JOIN table2 b on a.id = b.id 
WHERE a.first_name = @first_name
UNION
SELECT a.first_name, a.middle_name, a.age, b.address
FROM table1 a
INNER JOIN table2 b on a.id = b.id 
WHERE a.address = @address; 

这适用于

  • 只给出名字
  • 只给出地址
  • 两者都给出(在这种情况下,所有匹配至少一个条件的行都会返回)
  • 没有给出(在这种情况下不返回任何行)

对于这个查询,DBMS 可以使用一个索引first_name和另一个索引address(前提是您创建了这些索引)并且查询将非常快。

这个UNION查询毕竟只是另一种巧妙地使用该WHERE子句的方式WHERE a.first_name = @first_name OR a.address = @address。但是通过拆分查询,您可以向 DBMS 的优化器提示它可以将其视为两个单独的查询,它可以使用不同的索引。有了完美的优化器,这个提示就没有必要了,DBMS 会自己看到。我很确定 MySQL 当前的优化器需要这个提示。)


推荐阅读