MySQL наибольшее значение в строке? - PullRequest
0 голосов
/ 22 апреля 2010

Я использую 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

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

Ответы [ 6 ]

4 голосов
/ 22 апреля 2010

Вы ищете что-то вроде функции 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);
}
3 голосов
/ 22 апреля 2010

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

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

SELECT id, IF(col1>col2 AND col1>col3, 'col1', IF(col2>col3, 'col2', 'col3')) 
  AS column_with_greatest_value
FROM mytable;
1 голос
/ 22 апреля 2010

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

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. Кроме того, если у вас есть два столбца с одинаковыми значениями для одного и того же идентификатора, вы получите повторяющиеся строки.

0 голосов
/ 22 апреля 2010

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

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

0 голосов
/ 22 апреля 2010

В 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;
}

или что-то подобное ...

0 голосов
/ 22 апреля 2010

Этот запрос вернет максимальное значение независимо от значения 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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...