MySQL наибольшее значение в строке?

Я использую MySQL с PHP. Это похоже на мою таблицу: (я использую 3 значения, но их больше)

  id |  1 |  2 |  3
 --- + --- + --- + ----
 1 |  3 | 12 | -29
 2 |  5 | 8 | 8
 3 |  99 | 7 | NULL

Мне нужно получить имя столбца наибольшего значения в определенной строке. Он должен получить:

  id |  MAXCOL
 --- + -------
 1 |  2
 2 |  2
 3 |  1 

Есть ли какие-либо вопросы, которые будут делать это? Я пытался, но я не могу заставить его работать правильно.

Вы ищете что-то вроде функции GREATEST ? Например:

 SELECT id, GREATEST(col1, col2, col3) FROM tbl WHERE ... 

Объедините его с оператором CASE для получения имен столбцов:

 SELECT id, CASE GREATEST(COALESCE(`1`, -2147483646), COALESCE(`2`, -2147483646), COALESCE(`3`, -2147483646)) WHEN `1` THEN 1 WHEN `2` THEN 2 WHEN `3` THEN 3 ELSE 0 END AS maxcol FROM tbl WHERE ... 

Это некрасиво. Вам лучше следовать за предложением Билла Карвина и нормализовать его, или просто позаботиться об этом на PHP.

 function findcol($cmp, $arr, $cols=Null) { if (is_null($cols)) { $cols = array_keys($arr); } $name = array_shift($cols); foreach ($cols as $col) { if (call_user_func($cmp, $arr[$name], $arr[$col])) { $name = $col; } } return $name; } function maxcol($arr, $cols=Null) { return findcol(create_function('$a, $b', 'return $a < $b;'), $arr, $cols); } 

Это отличный пример того, как нормализация помогает упростить проектирование запросов. В первой нормальной форме вы создадите другую таблицу, чтобы все значения находились в одном столбце в отдельных строках.

Поскольку вы использовали повторяющиеся группы для хранения ваших значений в трех столбцах, вы можете найти столбец с наибольшим значением таким образом:

 SELECT id, IF(col1>col2 AND col1>col3, 'col1', IF(col2>col3, 'col2', 'col3')) AS column_with_greatest_value FROM mytable; 

Короткий ответ заключается в том, что нет простых способов сделать это с помощью запроса. Вам нужно будет транспонировать ваши данные, а затем определить наибольшее значение таким образом. Итак, что-то вроде:

 Select Id, ColumnName, Value From ( Select '1' As ColumnName, Id, [1] As Value From Table Union All Select '2', Id, [2] From Table Union All Select '3', Id, [3] From Table ) As Z Where Exists( Select 1 From ( Select '1' As ColumnName, Id, [1] As Value From Table Union All Select '2', Id, [2] From Table Union All Select '3', Id, [3] From Table ) As Z2 Where Z2.Id = Z.Id Group By Z2.Id Having Max(Z2.Value) = Z.Value ) Order By Id 

Это решение зависит от фиксированного набора столбцов, где вы в основном называете столбцы в запросах UNION ALL. Кроме того, если у вас есть два столбца с одинаковыми значениями для одного и того же идентификатора, вы получите повторяющиеся строки.

Этот запрос возвращает максимальное значение независимо от NULL

 SELECT MAX(value) FROM (SELECT 1 column_no, col1 value FROM anotherunamedtable UNION ALL SELECT 2, col2 FROM anotherunamedtable UNION ALL SELECT 3, col3 FROM anotherunamedtable) t 

Если вам действительно нужен номер столбца, тогда

 SELECT id, (SELECT column_no FROM (SELECT 1 column_no, col1 value FROM anotherunamedtable WHERE id = t.id UNION ALL SELECT 2, col2 FROM anotherunamedtable WHERE id = t.id UNION ALL SELECT 3, col3 FROM anotherunamedtable WHERE id = t.id) s ORDER BY max_value DESC LIMIT 1)) as column_no FROM anotherunamedtable t 

Но я думаю, что последний запрос мог бы выполнить исключительно ужасно. (Запросы не проверены)

На стороне php вы можете сделать что-то вроде этого:

 foreach ($rows as $key => $row) { $bestCol = $best = -99999; foreach ($row as $col => $value) { if ($col == 'id') continue; // skip ID column if ($value > $best) { $bestcol = $col; $best = $value; } } $rows[$key]['best'] = $bestCol; } 

Или что-то подобное …

Леса и деревья, вот тривиальное и быстрое решение (при условии, что я не пошатнулся); выражение просто ищет наибольший столбец в строке

 SELECT id, CASE COALESCE(col1, -2147483648) >= COALESCE(col2, -2147483648) WHEN CASE COALESCE(col2, -2147483648) >= COALESCE(col3, -2147483648) WHEN true THEN 1 ELSE CASE COALESCE(col1, -2147483648) >= COALESCE(col3, -2147483648) WHEN true THEN 1 ELSE 3 END END ELSE CASE COALESCE(col2, -2147483648) >= COALESCE(col3, -2147483648) WHEN true 2 ELSE 3 END END FROM table t 

версия с IF () может быть более читабельна, но выше должно быть немного лучше. Чтобы иметь дело с NULLS, было принято значение INT с минимумом -2147483648, выражение может быть переписано для явного обращения с нулями, но оно должно иметь ветвь в 8 различных случаях и остается в качестве упражнения для ОП.