Есть ли что-то эквивалентное argmax в SQL? - PullRequest
19 голосов
/ 29 декабря 2010

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

Ответы [ 8 ]

35 голосов
/ 29 декабря 2010

Не определенная функция, нет.

Существует множество способов написания запроса в зависимости от потребностей и функций, поддерживаемых базой данных.

Подзапрос:

При таком подходе существует риск возврата более одной строки, если какой-либо из них имеет одинаковое значение:

SELECT x.*
  FROM YOUR_TABLE x
 WHERE x.column = (SELECT MAX(y.column)
                     FROM YOUR_TABLE y)

Self Join:

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

SELECT x.*
  FROM YOUR_TABLE x
  JOIN (SELECT MAX(t.column) AS max_col
          FROM YOUR_TABLE t) y ON y.max_col = x.column

LIMIT / TOP:

SQL Server поддерживает TOP:

  SELECT TOP 1 
         x.*
    FROM YOUR_TABLE x
ORDER BY x.column DESC

Поддержка MySQL и PostgreSQL LIMIT:

  SELECT x.*
    FROM YOUR_TABLE x
ORDER BY x.column DESC
   LIMIT 1

Analytic - ROW_NUMBER ():

Это вернет одну строку и может быть настроено для предоставления наибольшего (или наименьшего) значения для группы.Однако это функциональные возможности Oracle 9i +, SQL Server 2005+ и PostgreSQL 8.4 +.

SELECT x.*
  FROM (SELECT y.*,
               ROW_NUMBER() OVER (ORDER BY y.column DESC) AS rank
          FROM YOUR_TABLE y) x
 WHERE x.rank = 1 

Analytic - DENSE_RANK ():

Может возвращать несколько строк, если они имеют одинаковое значениеи может быть настроен на предоставление самого высокого (или самого низкого) значения для каждой группы.Однако это функциональные возможности Oracle 9i +, SQL Server 2005+ и PostgreSQL 8.4+.

SELECT x.*
  FROM (SELECT y.*,
               DENSE_RANK() OVER (ORDER BY y.column DESC) AS rank
          FROM YOUR_TABLE y) x
 WHERE x.rank = 1 
1 голос
/ 19 апреля 2012

Не так давно я говорил с моим другом, и мы обсудили немного другой, но довольно практический вопрос, о разбиении некоторого «стола» на группы, а затем нахождении argmax / argmin для каждой полученной группы.В частности, давайте предположим, что у нас есть таблица, в которой мы храним все версии некоторых сущностей (имеется в виду историю всех сущностей, а активная сущность является самой последней на ее вершине (истории)), так как мы можем наиболее эффективно выбирать толькоактивные записи из этой таблицы (точнее - разбить на группы по entity_id (не row_id) и найти argmax в каждой группе по столбцу версии).Поэтому, поскольку одной из моих первых мыслей о том, «как исследовать эту проблему», были ключевые слова «oracle sql argmax ИЛИ argmin», я публикую здесь свой комментарий.

Как говорит мне мой друг, они используют [PARTITION BY] [PARTITION-BY] ключевое слово для их средств, и как я могу видеть из fetch-the-row-which-has-the-max-value-for-a-column и receive-values-по отношению к максимальным и минимальным строкам в оракуле есть два варианта использования DENSE_RANK с "OVER (ORDER BY ...)" и затем привязать этот ранг к 1 (как описано здесь ив " fetch-the-row-which-has-the-max-value-for-a-column ") или используйте что-то вроде "max (version) over (partition by entity_id / not"row_id /) max_version ", а затем связать" version = max_version "в том месте, где его вызывают, как описано в" получение значений, относящихся к максимальным и минимальным строкам в оракуле"(" fetch-the-row-which-has-the-max-value-for-a-column"), и мой друг говорит, что они предпочитают именно второй подход, как я понял,Бекаиспользовать его может потребовать меньше вычислений для каждой группы, поскольку он находит только максимальное значение и не должен полностью сортировать каждую группу, с другой стороны, если будет более одной записи с таким же максимальным значением, этот запросвыберет не только одну произвольно выбранную строку с максимальным значением «столбца порядка» (в нашем случае), но все строки (из группы), которые имеют это максимальное значение (так, чтобы можно было возвращать Argmax - не только как одну строку, но итакже как набор строк, где это достигается).

Кроме того, как я понял, ключевое слово [KEEP] [KEEP] [LAST] / [FIRST] в [Oracle SQL] [oracle-sql-ref]предназначены для охвата варианта использования argmin / armax, в обоих вариантах - с группировкой [GROUP BY] [GROUP-BY] или [PARTITION BY] [PARTITION-BY], но так как они предполагают, что результат Argmax и Argmin может содержать несколькотоже строки (не только одна строка), вы не можете просто выбрать «эту строку», используя конструкцию [KEEP] ... [FIRST] / [KEEP] ... [LAST], вместо этого вы должны использовать некоторую [функцию агрегирования][Oracle-SQL-Совокупные-Фunctions], для «извлечения» некоторого значения из «этих строк» ​​(Argmax-row), например (из [Oracle doc] [FIRST-Analytic-Example])

MAX(salary) KEEP (DENSE_RANK LAST ORDER BY commission_pct)
  OVER (PARTITION BY department_id) "Best"

где

KEEP (DENSE_RANK LAST ORDER BY commission_pct) OVER (PARTITION BY department_id)

предоставляет вам Argmax в виде набора строк (над отделом_id-group, с использованием в качестве критерия Commission_pct), а

MAX(salary)

предоставляет вам окончательную агрегацию по этим строкам Argmax (возможно, многочисленным).([Выбрать строку с максимальным значением] [Выбрать строку с максимальным значением] - обсуждение было отправной точкой для меня, чтобы я это понял).

Вот несколько справочных статей.

oracle-sql-ref Oracle-Sql-агрегатно-функции СОХРАНИТЬ ПЕРВЫЙ * 1 040 * ПЕРВЫЕ Аналитико-Example * * тысяча сорок один LAST Select-строка-с-Max-Value GROUP-BY PARTITION-BY ЗАКАЗАТЬ-BY-анализ

Функции SQL / query_partition_clause

DENSE_RANK MAX ROW_NUMBER

Вот несколько свободно цитируемых фрагментов о вышеупомянутых вещах.

с использованием [ROW_NUMBER] с [ORDER BY] [ORDER-BY-Analysis] и [PARTITION BY] [PARTITION-BY]

select row_id, entity_id, version, entity_value_1, entity_value_2
  from (select row_id, entity_id, version, entity_value_1, entity_value_2, 
          row_number()
            over (partition by entity_id order by version desc) as rank
        from Entities) as r
  where r.rank=1

с использованием [MAX] с [PARTITION BY] [PARTITION-BY]

select row_id, entity_id, version, max_version, entity_value_1, entity_value_2
  from (select row_id, entity_id, version, entity_value_1, entity_value_2, 
          max(version) over (partition by entity_id) as max_version
        from Entities) as r
  where r.version=r.max_version

с использованием [KEEP] [KEEP] [LAST] / [FIRST]для подавления возможности появления нескольких строк с одинаковыми entity_id и версией в результате (среди Argmax-строк выбирается уникальная строка с максимальным row_id)

SELECT row_id, entity_id, version, max_version, entity_value_1, entity_value_2
  FROM (SELECT 
          row_id, entity_id, version, entity_value_1, entity_value_2, 
          MAX(row_id) 
            KEEP (DENSE_RANK LAST ORDER BY version ASC)
            OVER (PARTITION BY entity_id) 
            AS row_id_for_max_version
        FROM Entities) as r
  WHERE r.row_id=r.row_id_for_max_version
0 голосов
/ 10 февраля 2015

- я взял имя таблицы = max_search и имя столбца A, B и C

и значения в таблице

A B C 10 20 30 60 40 50 80 90 70

Запрос: -

ВЫБРАТЬ (ДЕЛО КОГДА А> Б И А> С, ТО «А» КОГДА Б> А И Б> С, ТО 'Б' КОГДА C> B И C> A ТОГДА 'C' END) AS "Column_Name", наибольшее (A, B, C) AS Max_Value ОТ max_search;

Выход: - Column_Name Max_Value С 30 А 60 B 90

0 голосов
/ 29 декабря 2010

Я думаю, что следующее выберет каждую строку, где значение в столбце X равно максимальному значению столбца X:

SELECT * FROM [table] WHERE [Column X]=SELECT (MAX([Column X]) FROM [table])

0 голосов
/ 29 декабря 2010

Поскольку имя таблицы и имя столбца указаны, я оставляю их как заполнители. Запрос будет:

SELECT *
  FROM <YOUR_TABLE>
WHERE <YOUR_COLUMN_NAME> = (SELECT MAX(<YOUR_COLUMN_NAME>)
  FROM <YOUR_TABLE>)
0 голосов
/ 29 декабря 2010
SELECT
    *
FROM
    YourTable
WHERE
    YourColum = (SELECT MAX(YourColumn) FROM YourTable)
0 голосов
/ 29 декабря 2010

Если я правильно читаю ваш вопрос, следующий запрос должен это сделать (при условии, что наши столбцы имеют имена a, b и c и a - это столбец, который мы максимизируем):

select a,b,c from table where a=(select max(a) from table);

Конечно, если у вас есть более одной строки, где столбец а достигает своего максимума, вы получите более одной строки из запроса. Если вы хотите вернуть уникальную строку, вы можете добавить что-то вроде «order by b, c limit 1» или использовать другой способ ранжирования строк, в которых a достигает своего максимума.

0 голосов
/ 29 декабря 2010
SELECT *
FROM mytable
WHERE mycolumn = (
  SELECT MAX(mycolumn) FROM mytable
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...