我试图找到同一个表中一行的两列中的最小数字,但需要注意的是其中一列可能在某一行中为空。如果其中一列为null,我希望为该行返回的另一列中的值,因为在这种情况下,这是最低的非空列。如果我在MySQL 5.1中使用least()函数:
select least(1,null)
这会返回null,这不是我想要的。在这种情况下,我需要查询返回1.
我已经能够通过此查询获得我想要的结果:
select least(coalesce(col1, col2)) , coalesce(col2,col1))
只要col1和col2都不为null,每个coalesce语句将返回一个数字,而least()处理找到最低值。
有更简单/更快的方法吗?我在这个例子中使用MySQL,但欢迎使用一般的解决方案。
答案 0 :(得分:15)
不幸的是(对于你的情况)在MySQL 5.0.13(http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_least)中改变了LEAST的行为 - 只有当所有参数都为NULL时它才会返回NULL。
此更改甚至被报告为错误:http://bugs.mysql.com/bug.php?id=15610 但修复只针对MySQL文档,解释了新行为和兼容性中断。
您的解决方案是推荐的解决方法之一。另一个可以使用IF运算符:
SELECT IF(Col1 IS NULL OR Col2 IS NULL, COALESCE(Col1, Col2), LEAST(Col1,Col2))
答案 1 :(得分:4)
根据您所有值为null
的角落情况,我会选择更具可读性的语法(如果下面有两列,则更容易解决!)
SELECT LEAST( IFNULL(5, ~0 >> 1), IFNULL(10, ~0 >> 1) ) AS least_date;
-- Returns: 5
SELECT LEAST( IFNULL(null, ~0 >> 1), IFNULL(10, ~0 >> 1) ) AS least_date;
-- Returns: 10
SELECT LEAST( IFNULL(5, ~0 >> 1), IFNULL(null, ~0 >> 1) ) AS least_date;
-- Returns: 5
SELECT LEAST( IFNULL(null, ~0 >> 1), IFNULL(null, ~0 >> 1)) AS least_date
-- Returns: @MAX_VALUE (If you need to use it as default value)
SET @MAX_VALUE=~0 >> 1;
SELECT LEAST( IFNULL(null, @MAX_VALUE), IFNULL(null, @MAX_VALUE)) AS least_date;
-- Returns: @MAX_VALUE (If you need to use it as default value). Variables just makes it more readable!
SET @MAX_VALUE=~0 >> 1;
SELECT NULLIF(
LEAST( IFNULL(null, @MAX_VALUE), IFNULL(null,@MAX_VALUE)),
@MAX_VALUE
) AS least_date;
-- Returns: NULL
如果是
,这是我的首选方式NULL
NULL
)您希望非空的默认值大于任何可能的值或可以限制在某个阈值如果您质疑自己~0 >> 1
的含义:
它只是一个简短的说法"给我最多的可用数量"。另见:https://stackoverflow.com/a/2679152/2427579
更好的是,如果您只有两列,则可以使用:
SELECT LEAST( IFNULL(@column1, @column2), IFNULL(@column2, @column1) ) AS least_date;
-- Returns: NULL (if both columns are null) or the least value
答案 2 :(得分:3)
这可能会更好一些(可能必须转换为相应的MySql语法):
SELECT
CASE
WHEN Col1 IS NULL THEN Col2
WHEN Col2 IS NULL THEN Col1
ELSE Least(Col1, Col2)
END
另一种选择(虽然可能比较慢,但值得一试):
SELECT Col1
WHERE Col2 IS NULL
UNION
SELECT Col2
WHERE Col1 IS NULL
UNION
SELECT least(Col1, Col2)
WHERE Col1 IS NOT NULL AND Col2 IS NOT NULL
答案 3 :(得分:1)
为什么不将一列的值设置为等于另一列的值?
SELECT LEAST(IFNULL(COL1, COL2), IFNULL(COL2, COL1));
使用上面的代码,除非两者都为null,否则将忽略null值。
e.g。
COL1 = NULL,COL2 = 5
LEAST(IFNULL(NULL, 5), IFNULL(5, NULL)) -> LEAST(5, 5) -> 5
COL1 = 3,COL2 = NULL
LEAST(IFNULL(3, NULL), IFNULL(NULL, 3)) -> LEAST(3, 3) -> 3
COL1 = NULL,COL2 = NULL
LEAST(IFNULL(NULL, NULL), IFNULL(NULL, NULL)) -> LEAST(NULL, NULL) -> NULL
答案 4 :(得分:0)
选择 MIN(LEAST(COALESCE(COL1,COL2),COALESCE(COL2,CO1))) COL1不是空的 AND COL2不是空的;
答案 5 :(得分:0)
这是我解决的方法:
select coalesce(least(col1, col2), col1, col2)
如果一个值为NULL,则查询将返回第一个非NULL值。如果两个值都可以为NULL,则甚至可以将默认值添加为最后一个参数。
答案 6 :(得分:0)
我创建了一个处理任意数量日期的函数,方法是使用分隔符(CONCAT_WS)将它们连接起来作为该函数的第一个参数。
CONCAT_WS
除了动态数量的参数外,还将删除所有NULL日期;)
该函数接受两个参数:
CREATE FUNCTION `min_date`(`dates` TEXT, `delim` VARCHAR(10)) RETURNS DATE NO SQL DETERMINISTIC
BEGIN
DECLARE `result` DATE DEFAULT NULL;
DECLARE `count` TINYINT DEFAULT 0;
DECLARE `temp` DATE DEFAULT NULL;
IF `delim` IS NULL THEN SET `delim` = ','; END IF;
IF `dates` IS NOT NULL AND CHAR_LENGTH(`dates`) > 0 THEN
SET `count` = LENGTH(`dates`) - LENGTH(REPLACE(`dates`, `delim`, SPACE(CHAR_LENGTH(`delim`) - 1)));
WHILE `count` >= 0 DO
SET `temp` = SUBSTRING_INDEX(SUBSTRING_INDEX(`dates`, `delim`, `count` + 1), `delim`, -1);
IF `result` IS NULL OR `result` > `temp` THEN SET `result` = `temp`; END IF;
SET `count` = `count` - 1;
END WHILE;
END IF;
RETURN `result`;
END
然后,您可以在日期字段的任何组合中使用或作为静态字符串使用(只要有效日期或NULL):
SELECT min_date(CONCAT_WS(',', `date_column_1`, NULL, '2019-03-04', `date_column_2`), ',') AS `min_date`
答案 7 :(得分:0)
下面是一个简单的解决方案。
如果要查找最小的非空值,则可以将IFNULL与第二个参数用作“ INT限制”
ORDER BY LEAST(
IFNULL(properties.sale_value, 2147483647),
IFNULL(properties.rental_value, 2147483647),
IFNULL(properties.daily_rental_value, 2147483647)
) ASC
如果要查找最大的非null值,则可以使用IFNULL,第二个参数为1(或者小于极限的第一个负值,如果不知道,请使用负整数限制)
ORDER BY GREATEST(
IFNULL(properties.sale_value, 1),
IFNULL(properties.rental_value, 1),
IFNULL(properties.daily_rental_value, 1)
) ASC