Я использую 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 различных случаях и остается в качестве упражнения для ОП.