Как найти наименьший ненулевой столбец в одной конкретной строке в SQL?
Я пытаюсь найти самое низкое число в двух столбцах строки в той же таблице, с оговоркой, что один из столбцов может быть нулевым в определенной строке. Если один из столбцов имеет значение null, я хочу, чтобы значение в другом столбце возвращалось для этой строки, так как в этом случае это самый низкий столбец, отличный от нуля. Если я использую функцию minimum() в MySQL 5.1:
select least(1,null)
Это возвращает null, что не то, что я хочу. Мне нужен запрос для возврата 1 в этом случае.
Мне удалось получить результат, который я хочу получить с помощью этого запроса:
select least(coalesce(col1, col2)) , coalesce(col2,col1))
Пока col1 и col2 оба не равны нулю, каждый оператор coalesce возвращает число, а наименьшее() обрабатывает поиск самого низкого.
Есть ли более простой/быстрый способ сделать это? Я использую MySQL в этом случае, но общие решения приветствуются.
Ответы
Ответ 1
К сожалению (для вашего случая) поведение LEAST было изменено в MySQL 5.0.13 (http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_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))
Ответ 2
Это может немного улучшить (возможно, придется преобразовать в соответствующий синтаксис 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
В зависимости от ситуации вашего угла с учетом всех значений 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
:
Это всего лишь короткая рука для того, чтобы сказать "Дайте мне наибольшее количество доступных". См. Также: fooobar.com/questions/65809/...
Еще лучше, если у вас есть только два столбца, вы можете использовать:
SELECT LEAST( IFNULL(@column1, @column2), IFNULL(@column2, @column1) ) AS least_date;
-- Returns: NULL (if both columns are null) or the least value
Ответ 4
Почему бы не установить значение одного столбца равным другому столбцу, когда оно равно NULL?
SELECT LEAST(IFNULL(COL1, COL2), IFNULL(COL2, COL1));
с кодом выше, нулевое значение будет проигнорировано, если оба значения равны нулю.
например.
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