返回一个值,即使没有结果

76

我有一个简单的查询,针对给定的id返回一个非空整数字段:

SELECT field1 FROM table WHERE id = 123 LIMIT 1;

问题是如果找不到ID,则结果集为空。我需要查询始终返回一个值,即使没有结果。

我已经让这个东西工作了,但我不喜欢它,因为它运行了两次相同的子查询:

SELECT IF(EXISTS(SELECT 1 FROM table WHERE id = 123) = 1, (SELECT field1 FROM table WHERE id = 123 LIMIT 1), 0);

如果该行存在,则返回field1,否则返回0。有没有任何改进的方法?

谢谢!

在查看一些评论和答案后进行编辑:是的,它必须在一个单一的查询语句中,并且我不能使用计数技巧,因为我只需要返回一个值(FYI我使用Java/Spring方法SimpleJdbcTemplate.queryForLong()运行查询)。


这需要在一个查询语句中完成吗?否则,你可以声明一个带有默认值的变量,将其选入,然后选择该变量。 - Paul Bellora
10个回答

155

MySQL有一个函数,用于在结果为空时返回一个值。您可以在整个查询上使用它:

SELECT IFNULL( (SELECT field1 FROM table WHERE id = 123 LIMIT 1) ,'not found');

3
把整个查询语句放在IFNULL里是个好点子!其实我也尝试过类似的写法:SELECT IFNULL(field1, 0) FROM table WHERE id = 123 LIMIT 1; 但它没有起作用(没有结果),我没想到把整个查询语句放在IFNULL里面... - Maxime Laval
4
这是关于一个经常被提问的问题在 Stack Overflow 上最好的答案。值得一提的是,IFNULL() 的作用也可以由 COALESCE() 替代。不确定它们之间是否有性能上的区别,但我习惯使用 COALESCE(),因为更容易记住。 - But those new buttons though..
COALESCE() 函数将继续查找不为空的值,直到具有超过一个参数。http://www.techonthenet.com/mysql/functions/coalesce.php - illusionJJ
这需要运行两次SELECT语句。一次是检查是否能找到,另一次是实际查找。这会使MySQL服务器的负载加倍,但结果却完全相同。请参见MarkNHopGood提供的解决方案。 - HoldOffHunger
1
点赞!从来没有想过在整个查询中使用IFNULL - Ju Oliveira

41

1
非常有用!!我用“null”(不带引号)替换了“default_value_if_no_record”,并且它产生了期望的输出。完美,谢谢! - HoldOffHunger
1
聪明绝顶,我的朋友! - Oooogi
4
是的,这是一篇相当老的帖子,但我想提到union不保证任何顺序,因此返回的那个1条记录完全有可能是默认行而不是结果。我不知道任何实现会对这个简单的结果集进行洗牌,但依赖这种行为真的不安全。文档页面提到了这一点,并提出了一个解决方案,涉及使用虚拟排序列,如果你真的想要使用这种方法,但它开始变得有点混乱。 - A C
有时候MySQL可能会返回空字符串,而UNION无法捕获。解决方案:(SELECT field1 FROM table WHERE id = 123 AND field1 <> '') UNION (SELECT 'default_value_if_no_record') LIMIT 1; - Widmo
正如@AC所提到的,UNION不能保证顺序,但如果您想返回一个简单的Y或N标志,您可以给该字段取别名并使用ORDER BY来确保您获得正确的顺序:(SELECT IF(field IS NULL, 'N', 'Y') AS flag FROM table WHERE id = 123) UNION (SELECT 'N' AS flag) ORDER BY flag DESC LIMIT 1; - MarkusMulholland

21
您可以包含 count(id)。它将始终返回数量。
select count(field1), field1 from table where id = 123 limit 1;

http://sqlfiddle.com/#!2/64c76/4


这是一个指向http://sqlfiddle.com/#!2/64c76/4的超链接。

甚至可以这样写:SELECT 1, field FROM table WHERE ... - nico
不行,那样做不行。min、max、sum或其他大多数函数也不行。基本上我总是坚持使用count,因为我知道它有效。 - Andreas Wederbrand
哦,你说得对,我以为它能正常工作,但实际上我刚刚尝试了一下,发现它并不能正常工作。 - nico
2
无法在此处使用 GROUP by。 - PodTech.io
@Uncle Iroh 当使用 group by 时它不起作用。我在我的数据库中尝试了 select ifnull(sum(1), 0) from part where 1 = 2 group by part_code;,但它没有返回任何行。 - user5685187
显示剩余2条评论

8

你可以使用COALESCE函数。

SELECT COALESCE(SUM(column),0)
FROM   table

2
如果有人想要将结果插入到一个变量中,并在存储过程中使用它,可以按照以下方式操作:
DECLARE date_created INT DEFAULT 1;
SELECT IFNULL((SELECT date FROM monthly_comission WHERE date = date_new_month LIMIT 1), 0) 
INTO date_created 
WHERE IFNULL((SELECT date FROM monthly_comission WHERE date = date_new_month LIMIT 1), 0) = 0;

通过这个代码,你会将变量“date_created”存储为1或0(如果没有返回值的话)。


0

使用 LEFT OUTER JOIN 进行搜索。我不知道 MySQL 是否允许在连接子句中使用内联 VALUES,但您可以为此目的预定义表。


0
如果您想始终返回一个值而不是空值,可以将 count 与 coalesce 结合使用:
select count(field1), coalesce(field1,'any_other_default_value') from table;

这是因为 count 会强制 MySQL 始终返回一个值(如果没有值则返回 0),而 coalesce 则会强制 MySQL 始终放置一个非空值。


0

k-a-f的回答适用于选择一个列,如果要选择多个列,我们可以:

DECLARE a BIGINT DEFAULT 1;
DECLARE b BIGINT DEFAULT "name";

SELECT id, name from table into a,b;

那么我们只需要检查a和b的值即可。


0

如果您只想要一个结果,那么您可以使用聚合函数。因为聚合函数在没有找到值时会打印 null。 我可以给您两个解决方案。

解决方案1:

SELECT
      max(field1)
FROM 
(SELECT field1 FROM table WHERE id = 123);

解决方案2,
(SELECT field1 FROM table WHERE id = 123 LIMIT 1)
UNION
(SELECT NULL)
LIMIT 1;

0
我刚刚遇到了几乎相同的情况,只是查询有时返回0行,有时可能返回多行。对于多行,你不能像K.A.F所描述的那样使用IFNULL函数。在这种情况下,你可以在一个虚拟字段上使用LEFT JOIN来强制MySQL返回一个NULL记录,而不是返回空行。然后,你可以使用CASE语句将该null转换为更具描述性的内容。
例如:
SELECT CASE WHEN b.field1 is NULL then "No Records" else b.field1 end as "field1" from
(SELECT '1' as dummy from table limit 1) a
LEFT JOIN 
(SELECT field1, '1' as dummy FROM table WHERE id = 123) b
ON a.dummy = b.dummy;

如果"field1"没有记录,LEFT JOIN将强制返回一个"NULL",然后SELECT CASE将其转换为"无记录"。如果"field1"有记录,将返回这些记录。
就记录而言,我的情况与Grafana仪表板中的变量有关。该变量有时会返回0条记录,并且由于该变量在查询的WHERE子句中用于一个面板的"IN"列表中,变量的空列表会导致查询出错。使用上述方法使我能够返回一个描述性的"NULL"值,适当地通知用户,并使面板查询行为适当。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接