SQL выбирает только столбцы с максимальным значением в столбце [дубликаты]

839

У меня есть эта таблица для документов (упрощенная версия здесь):

+------+-------+--------------------------------------+
| id   | rev   | content                              |
+------+-------+--------------------------------------+
| 1    | 1     | ...                                  |
| 2    | 1     | ...                                  |
| 1    | 2     | ...                                  |
| 1    | 3     | ...                                  |
+------+-------+--------------------------------------+

Как выбрать одну строку на один идентификатор и только наибольший оборот?
С приведенными выше данными результат должен содержать две строки: [1, 3, ...] и [2, 1, ..]. Я использую MySQL.

В настоящее время я использую проверки в цикле while для обнаружения и перезаписи старых revs из набора результатов. Но является ли это единственным методом достижения результата? Разве нет решения SQL?

Обновление
Как показывают ответы, есть SQL-решение, а здесь демо-версия sqlfiddle.

Обновление 2
Я заметил, что после добавления вышеуказанного sqlfiddle скорость, с которой встал вопрос, превзошла скорость ответов. Это не было намерением! Скрипка основана на ответах, особенно на принятом ответе.

Показать ещё 4 комментария
Теги:
aggregate-functions
greatest-n-per-group

30 ответов

1409
Лучший ответ

На первый взгляд...

Все, что вам нужно, это предложение GROUP BY с функцией агрегации MAX:

SELECT id, MAX(rev)
FROM YourTable
GROUP BY id

Это так просто, не так ли?

Я просто заметил, что вам нужен столбец content.

Это очень распространенный вопрос в SQL: найдите все данные для строки с некоторым максимальным значением в столбце для каждого идентификатора группы. Я много слышал о своей карьере. Фактически, это был один из вопросов, которые я ответил в своем текущем техническом интервью.

На самом деле настолько распространено, что сообщество StackOverflow создало один тег, чтобы справиться с такими вопросами: .

В принципе, у вас есть два подхода к решению этой проблемы:

Соединение с простым group-identifier, max-value-in-group Подзапросом

В этом подходе вы сначала найдете group-identifier, max-value-in-group (уже разрешенный выше) в подзапросе. Затем вы присоединяете свою таблицу к подзапросу с равенством как на group-identifier, так и на max-value-in-group:

SELECT a.id, a.rev, a.contents
FROM YourTable a
INNER JOIN (
    SELECT id, MAX(rev) rev
    FROM YourTable
    GROUP BY id
) b ON a.id = b.id AND a.rev = b.rev

Левое соединение с помощью себя, настройка условий соединения и фильтров

В этом подходе вы оставили соединение с самим собой. Равенство, конечно же, идет в group-identifier. Затем два умных перемещения:

  • Второе условие объединения имеет левое боковое значение меньше правого значения
  • Когда вы выполните шаг 1, строки (ы), которые на самом деле имеют максимальное значение, будут иметь NULL в правой части (это a LEFT JOIN, помните?). Затем мы фильтруем объединенный результат, показывая только строки, где правая сторона NULL.

Итак, вы закончите:

SELECT a.*
FROM YourTable a
LEFT OUTER JOIN YourTable b
    ON a.id = b.id AND a.rev < b.rev
WHERE b.id IS NULL;

Заключение

Оба подхода приносят точный результат.

Если у вас есть две строки с max-value-in-group для group-identifier, обе строки будут в результате в обоих подходах.

Оба подхода совместимы с SQL ANSI, поэтому они будут работать с вашей любимой РСУБД, независимо от ее "вкуса".

Оба подхода также совместимы с производительностью, однако ваш пробег может варьироваться (РСУБД, структура БД, индексы и т.д.). Поэтому, когда вы выбираете один подход по сравнению с другим, ориентир. И убедитесь, что вы выбрали тот, который имеет для вас большой смысл.

  • 1
    Первая версия была намного проще, разве не получилось бы получить результат, добавив больше столбцов? Я также должен обслуживать where : select id, max(rev), content, etc., etc., from the_table where proj_id = $pid group by id
  • 8
    Я знаю, что MySQL позволяет вам добавлять неагрегированные поля в запрос «сгруппированы по», но я нахожу это бессмысленным. Попробуйте запустить этот select id, max(rev), rev from YourTable group by id и вы поймете, что я имею в виду. Не торопитесь и попытайтесь понять это
Показать ещё 31 комментарий
181

Мое предпочтение заключается в том, чтобы использовать как можно меньше кода...

Вы можете сделать это, используя IN попробуйте следующее:

SELECT * 
FROM t1 WHERE (id,rev) IN 
( SELECT id, MAX(rev)
  FROM t1
  GROUP BY id
)

на мой взгляд, он менее сложный... легче читать и поддерживать.

  • 23
    Любопытно - в каком движке базы данных мы можем использовать этот тип предложения WHERE? Это не поддерживается в SQL Server.
  • 18
    oracle & mysql (не уверен насчет других баз данных извините)
Показать ещё 12 комментариев
54

Еще одно решение - использовать коррелированный подзапрос:

select yt.id, yt.rev, yt.contents
    from YourTable yt
    where rev = 
        (select max(rev) from YourTable st where yt.id=st.id)

Наличие индекса (id, rev) делает подзапрос почти как простой поиск...

Ниже приведены сравнения с решениями в ответе @AdrianCarneiro (subquery, leftjoin), основанные на измерениях MySQL с таблицей InnoDB размером ~ 1 миллион записей, размер группы: 1-3.

В то время как для полного сканирования таблицы подзапросы/левые/коррелированные тайминги относятся друг к другу как 6/8/9, когда дело доходит до прямого поиска или партии (id in (1,2,3)), подзапрос выполняется намного медленнее, чем остальные (из-за повторной передачи подзапрос). Однако я не мог отличать ледяные и коррелированные решения в скорости.

Наконец, поскольку leftjoin создает n * (n + 1)/2, объединяется в группы, его производительность может сильно зависеть от размера групп...

  • 0
    Пока это единственный, который работал так, как мне было нужно, спасибо (нужно совпадать по имени, а не по идентификатору)
  • 2
    Я не думаю, что это работает, если rev не уникален.
Показать ещё 4 комментария
34

Я не могу ручаться за производительность, но вот трюк, вдохновленный ограничениями Microsoft Excel. Он имеет некоторые хорошие функции.

GOOD STUFF

  • Он должен принудительно вернуть только одну "максимальную запись", даже если есть галстук (иногда полезный)
  • Он не требует соединения

ПОДХОД

Это немного уродливо и требует, чтобы вы знали что-то о диапазоне допустимых значений столбца rev. Предположим, что мы знаем, что столбец rev - это число от 0,00 до 999, включая десятичные числа, но что только две цифры справа от десятичной точки (например, 34.17 будет действительным значением).

Суть в том, что вы создаете единый синтетический столбец путем конкатенации/упаковки первичного поля сравнения вместе с данными, которые вы хотите. Таким образом, вы можете заставить агрегированную функцию SQL MAX() возвращать все данные (поскольку она была упакована в один столбец). Затем вам нужно распаковать данные.

Вот как он выглядит с приведенным выше примером, написанным на SQL

SELECT id, 
       CAST(SUBSTRING(max(packed_col) FROM 2 FOR 6) AS float) as max_rev,
       SUBSTRING(max(packed_col) FROM 11) AS content_for_max_rev 
FROM  (SELECT id, 
       CAST(1000 + rev + .001 as CHAR) || '---' || CAST(content AS char) AS packed_col
       FROM yourtable
      ) 
GROUP BY id

Упаковка начинается с того, что для того, чтобы столбец rev был числом известных символов, независимо от значения rev, чтобы, например,

  • 3.2 становится 1003.201
  • 57 становится 1057.001
  • 923.88 становится 1923.881

Если вы это сделаете правильно, сравнение строк двух чисел должно давать то же самое "max", что и числовое сравнение двух чисел, и легко преобразовать обратно к исходному номеру с помощью функции подстроки (которая доступна в одной форме или другой почти везде).

  • 0
    Отличное решение, оно работает намного быстрее, чем соединение и другие предлагаемые решения.
31

Я смущен, что ни один из ответов не предложил решение функции SQL-окна:

SELECT a.id, a.rev, a.contents
  FROM (SELECT id, rev, contents,
               ROW_NUMBER() OVER (PARTITION BY id ORDER BY rev DESC) rank
          FROM YourTable) a
 WHERE a.rank = 1 

Добавлен в стандарт SQL Стандарт ANSI/ISO SQL: 2003 и более поздние версии с ANSI/ISO Standard SQL: 2008, теперь доступны функции окна (или окна) со всеми основными поставщиками. Существует больше типов ранговых функций, доступных для решения проблемы связи: RANK, DENSE_RANK, PERSENT_RANK.

  • 0
    Я думаю, что это менее интуитивно и потенциально менее понятно - но это может определенно работать / быть решением.
  • 4
    интуиция - хитрая вещь. Я нахожу его более интуитивным, чем другие ответы, поскольку он строит явную структуру данных, которая отвечает на вопрос. Но, опять же, интуиция - это другая сторона предвзятости ...
Показать ещё 4 комментария
20

Я думаю, что это самое простое решение:

SELECT *
FROM
    (SELECT *
    FROM Employee
    ORDER BY Salary DESC)
AS employeesub
GROUP BY employeesub.Salary;
  • SELECT *: вернуть все поля.
  • FROM Employee: найденная таблица.
  • (SELECT *...) подзапрос: вернуть всех людей, отсортированных по зарплате.
  • GROUP BY employeesub.Salary:: Принудительно, чтобы возвращаемый результат отображал верхнюю сортировку, Заработная строка каждого сотрудника.

Если вам нужна только одна строка, это еще проще:

SELECT *
FROM Employee
ORDER BY Employee.Salary DESC
LIMIT 1

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

  • ORDER BY Employee.Salary DESC: закажите результаты по зарплате с наивысшими зарплатами.
  • LIMIT 1: возвращает только один результат.

Понимание этого подхода, решение любой из этих подобных проблем становится тривиальным: получить сотрудника с наименьшей зарплатой (изменить DESC на ASC), получить топ-десять сотрудников (изменить LIMIT 1 до LIMIT 10), отсортировать с помощью другого поля ( измените ЗАКАЗАТЬ от Employee.Salary к ORDER BY Employee.Commission) и т.д.

  • 1
    Это не отвечает на вопрос. Вопрос заключается в том, как получить данные для одной строки (как было задано, «одна строка на идентификатор») в групповом запросе, где значение x - это максимум в каждой группе строк. Например, таблица заказов клиентов с несколькими заказами на клиента, где вы хотите получить самый большой заказ для каждого клиента. Ваш запрос вполне может вернуть более одной строки для каждого клиента (если, например, два самых больших заказа были размещены одним и тем же клиентом).
  • 0
    "одна строка на ID" <- продолжайте читать, пожалуйста, и вы увидите "и только самое большое". Это логически эквивалентно только величайшему.
Показать ещё 6 комментариев
15

Что-то вроде этого?

SELECT yourtable.id, rev, content
FROM yourtable
INNER JOIN (
    SELECT id, max(rev) as maxrev FROM yourtable
    WHERE yourtable
    GROUP BY id
) AS child ON (yourtable.id = child.id) AND (yourtable.rev = maxrev)
  • 0
    Те, кто не присоединился, не стали бы это сокращать?
  • 1
    Если они работают, то они тоже в порядке.
Показать ещё 2 комментария
6

Поскольку это самый популярный вопрос в отношении этой проблемы, я снова отправлю еще один ответ на этот вопрос:

Похоже, что есть более простой способ сделать это (но только в MySQL):

select *
from (select * from mytable order by id, rev desc ) x
group by id

Пожалуйста, кредитный ответ пользователя Bohemian в этот вопрос за предоставление такого краткого и элегантного ответа на эту проблему.

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

  • 7
    За исключением того, что это неправильно, поскольку нет никакой гарантии, что порядок внутреннего запроса что-либо значит, и не всегда гарантируется, что GROUP BY будет занимать первую встреченную строку. По крайней мере, в MySQL, и я бы предположил, все остальные. На самом деле я предполагал, что MySQL просто проигнорирует весь ORDER BY. Любая будущая версия или изменение конфигурации могут нарушить этот запрос.
  • 0
    @Jannes это интересное замечание :) Я приветствую вас ответить на мой вопрос, предоставив доказательства: stackoverflow.com/questions/26301877/…
Показать ещё 2 комментария
4

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

SELECT id, MAX(rev) AS rev
 , 0+SUBSTRING_INDEX(GROUP_CONCAT(numeric_content ORDER BY rev DESC), ',', 1) AS numeric_content
FROM t1
GROUP BY id

Да, это выглядит ужасно (преобразование в строку и обратно и т.д.), но по моему опыту это обычно быстрее, чем другие решения. Возможно, это только для моих случаев использования, но я использовал его на таблицах с миллионами записей и множеством уникальных идентификаторов. Может быть, потому, что MySQL довольно плохо оптимизирует другие решения (по крайней мере, в 5,0 дней, когда я придумал это решение).

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

В любом случае вышеупомянутое не работает напрямую, если ваше поле содержимого уже является текстом. В этом случае вы, вероятно, захотите использовать другой разделитель, например, \0. Вы также быстрее столкнетесь с префиксом group_concat_max_len.

4

Мне нравится использовать решение на основе NOT EXIST для этой проблемы:

SELECT id, rev
FROM YourTable t
WHERE NOT EXISTS (
   SELECT * FROM YourTable t WHERE t.id = id AND rev > t.rev
)
  • 1
    да, не существует, как это обычно было предпочтительным способом, а не левым соединением. В старых версиях SQL-сервера это было быстрее, хотя я думаю, что теперь это не имеет значения. Я обычно делаю SELECT 1 вместо SELECT *, опять же, потому что в предыдущих версиях это было быстрее.
3

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

select * from
(select * from table_name
order by id,rev desc) temp
group by id 
  • 0
    Это работает нормально для небольших таблиц, но занимает 6 проходов по всему набору данных, поэтому не быстро для больших таблиц.
  • 0
    Этот запрос мне был нужен, потому что были задействованы и другие столбцы.
2

Я бы использовал это:

select t.*
from test as t
join
   (select max(rev) as rev
    from test
    group by id) as o
on o.rev = t.rev

Подзапрос SELECT не слишком эффективен, но в разделе JOIN кажется полезным. Я не эксперт в оптимизации запросов, но я пробовал в MySQL, PostgreSQL, FireBird и работает очень хорошо.

Вы можете использовать эту схему в нескольких соединениях и с предложением WHERE. Это мой рабочий пример (решение идентично вашей проблеме с таблицей "твердое" ):

select *
from platnosci as p
join firmy as f
on p.id_rel_firmy = f.id_rel
join (select max(id_obj) as id_obj
      from firmy
      group by id_rel) as o
on o.id_obj = f.id_obj and p.od > '2014-03-01'

Его спрашивают на таблицах с подростками таких записей, и он занимает менее 0,01 секунды на действительно не слишком сильной машине.

Я бы не использовал предложение IN (как упоминается выше). IN предоставляется для использования с короткими списками констант, а не как фильтр запросов, построенный на подзапросе. Это связано с тем, что подзапрос в IN выполняется для каждой отсканированной записи, которая может сделать запрос очень медленным.

  • 0
    Я думаю, что использование этого подзапроса в качестве CTE может по крайней мере улучшить производительность
  • 0
    Привет! Для меня это выглядит так, как будто ваш первый запрос нуждается ... and o.id = t.id в конце (и для этого подзапрос должен возвращать id ). Не так ли?
2

Как насчет этого:

select all_fields.*  
from  (select id, MAX(rev) from yourtable group by id) as max_recs  
left outer join yourtable as all_fields  
on max_recs.id = all_fields.id
1

Здесь другое решение для получения записей только с полем, которое имеет максимальное значение для этого поля. Это работает для SQL400, на котором я работаю. В этом примере записи с максимальным значением в поле FIELD5 будут получены следующим оператором SQL.

SELECT A.KEYFIELD1, A.KEYFIELD2, A.FIELD3, A.FIELD4, A.FIELD5
  FROM MYFILE A
 WHERE RRN(A) IN
   (SELECT RRN(B) 
      FROM MYFILE B
     WHERE B.KEYFIELD1 = A.KEYFIELD1 AND B.KEYFIELD2 = A.KEYFIELD2
     ORDER BY B.FIELD5 DESC
     FETCH FIRST ROW ONLY)
1

SELECT * ОТ сотрудника где Employee.Salary in (выберите max (зарплата) из группы Employee Employe_id) ORDER BY Employee.Salary

1

Ни один из этих ответов не работал у меня.

Это то, что сработало для меня.

with score as (select max(score_up) from history)
select history.* from score, history where history.score_up = score.max
1

вот еще одно решение, которое поможет кому-то

Select a.id , a.rev, a.content from Table1 a
inner join 
(SELECT id, max(rev) rev FROM Table1 GROUP BY id) x on x.id =a.id and x.rev =a.rev
1

Многие, если не все, другие ответы здесь подходят для небольших наборов данных. Для масштабирования требуется больше внимания. См. здесь.

В нем обсуждается несколько более быстрых способов сделать groupwise max и top-N для каждой группы.

1

Отсортировано поле rev в обратном порядке, а затем сгруппировано по id, которое дало первую строку каждой группы, которая является самой высокой величиной rev.

SELECT * FROM (SELECT * FROM table1 ORDER BY id, rev DESC) X GROUP BY X.id;

Протестировано в http://sqlfiddle.com/ со следующими данными

CREATE TABLE table1
    (`id` int, `rev` int, `content` varchar(11));

INSERT INTO table1
    (`id`, `rev`, `content`)
VALUES
    (1, 1, 'One-One'),
    (1, 2, 'One-Two'),
    (2, 1, 'Two-One'),
    (2, 2, 'Two-Two'),
    (3, 2, 'Three-Two'),
    (3, 1, 'Three-One'),
    (3, 3, 'Three-Three')
;

Это дало следующий результат в MySql 5.5 и 5.6

id  rev content
1   2   One-Two
2   2   Two-Two
3   3   Three-Two
  • 0
    Эта техника раньше работала, но больше не работала. См. Mariadb.com/kb/en/mariadb/…
  • 1
    Исходный тег вопроса - «mysql», и я очень четко заявил, что мое решение было протестировано с Mysql 5.5 и 5.6 на sqlfiddle.com. Я предоставил все шаги, чтобы самостоятельно проверить решение. Я не сделал никаких ложных утверждений, что мое решение работает с Mariadb. Mariadb - это не Mysql, это просто замена Mysql, принадлежащая двум разным компаниям. Ваш комментарий поможет всем, кто пытается реализовать его в Mariadb, но мой пост ни в коем случае не заслуживает отрицательного голосования, поскольку он четко отвечает на заданный вопрос.
Показать ещё 2 комментария
1

Если кто-то ищет Linq verson, это, похоже, работает для меня:

public static IQueryable<BlockVersion> LatestVersionsPerBlock(this IQueryable<BlockVersion> blockVersions)
{
    var max_version_per_id = blockVersions.GroupBy(v => v.BlockId)
        .Select( v => new { BlockId = v.Key, MaxVersion = v.Max(x => x.Version) } );    

    return blockVersions.Where( v => max_version_per_id.Any(x => x.BlockId == v.BlockId && x.MaxVersion == v.Version) );
}
1

Мне нравится делать это путем ранжирования записей в каком-то столбце. В этом случае значения ранга rev сгруппированы по id. Те, у кого выше rev, будут иметь более низкий рейтинг. Таким образом, наивысший rev будет иметь рейтинг 1.

select id, rev, content
from
 (select
    @rowNum := if(@prevValue = id, @rowNum+1, 1) as row_num,
    id, rev, content,
    @prevValue := id
  from
   (select id, rev, content from YOURTABLE order by id asc, rev desc) TEMP,
   (select @rowNum := 1 from DUAL) X,
   (select @prevValue := -1 from DUAL) Y) TEMP
where row_num = 1;

Не уверен, что введение переменных делает все это медленнее. Но, по крайней мере, я не дважды запрашиваю YOURTABLE.

  • 0
    Только попробовал подход в MySQL. Oracle имеет аналогичную функцию для ранжирования записей. Идея тоже должна работать.
  • 1
    Чтение и запись переменной в операторе выбора не определено в MySQL, хотя отдельные версии дают ответ, который вы можете ожидать для определенного синтаксиса, включающего выражения регистра.
1

Вот хороший способ сделать это

Используйте следующий код:

with temp as  ( 
select count(field1) as summ , field1
from table_name
group by field1 )
select * from temp where summ = (select max(summ) from temp)
1

НЕ mySQL, но для других людей, которые находят этот вопрос и используют SQL, другим способом решения проблемы является использование Cross Apply в MS SQL

WITH DocIds AS (SELECT DISTINCT id FROM docs)

SELECT d2.id, d2.rev, d2.content
FROM DocIds d1
CROSS APPLY (
  SELECT Top 1 * FROM docs d
  WHERE d.id = d1.id
  ORDER BY rev DESC
) d2

Вот пример в SqlFiddle

  • 0
    очень медленный по сравнению с другими методами - группировка, окна, не существует
1

Это решение делает только один выбор из YourTable, поэтому он быстрее. Он работает только для MySQL и SQLite (для SQLite удаляет DESC) в соответствии с тестом на sqlfiddle.com. Возможно, он может быть настроен для работы на других языках, с которыми я не знаком.

SELECT *
FROM ( SELECT *
       FROM ( SELECT 1 as id, 1 as rev, 'content1' as content
              UNION
              SELECT 2, 1, 'content2'
              UNION
              SELECT 1, 2, 'content3'
              UNION
              SELECT 1, 3, 'content4'
            ) as YourTable
       ORDER BY id, rev DESC
   ) as YourTable
GROUP BY id
  • 0
    Это не похоже на работу для общего случая. И это не работает вообще в PostgreSQL, возвращая: ERROR: column "your table.reb" must appear in the GROUP BY clause or be used in an aggregate function LINE 1: SELECT *
  • 0
    Извините, я не уточнил первый раз, на каком языке это работает.
0

Другой способ выполнения задания - использовать аналитическую функцию MAX() в предложении OVER PARTITION

SELECT t.*
  FROM
    (
    SELECT id
          ,rev
          ,contents
          ,MAX(rev) OVER (PARTITION BY id) as max_rev
      FROM YourTable
    ) t
  WHERE t.rev = t.max_rev 

Другое решение OVER PARTITION, уже зарегистрированное в этом сообщении,

SELECT t.*
  FROM
    (
    SELECT id
          ,rev
          ,contents
          ,ROW_NUMBER() OVER (PARTITION BY id ORDER BY rev DESC) rank
      FROM YourTable
    ) t
  WHERE t.rank = 1 

Этот 2 SELECT хорошо работает на Oracle 10g.

0

Я использовал ниже, чтобы решить свою проблему. Сначала я создал временную таблицу и вставил максимальное значение rev на уникальный идентификатор.

CREATE TABLE #temp1
(
    id varchar(20)
    , rev int
)
INSERT INTO #temp1
SELECT a.id, MAX(a.rev) as rev
FROM 
    (
        SELECT id, content, SUM(rev) as rev
        FROM YourTable
        GROUP BY id, content
    ) as a 
GROUP BY a.id
ORDER BY a.id

Затем я присоединил эти максимальные значения (# temp1) ко всем возможным комбинациям id/content. Делая это, я, естественно, отфильтровываю не максимальные комбинации id/content, и оставляю их только с максимальными значениями rev для каждого.

SELECT a.id, a.rev, content
FROM #temp1 as a
LEFT JOIN
    (
        SELECT id, content, SUM(rev) as rev
        FROM YourTable
        GROUP BY id, content
    ) as b on a.id = b.id and a.rev = b.rev
GROUP BY a.id, a.rev, b.content
ORDER BY a.id
-1
select * from yourtable
group by id
having rev=max(rev);
-2
SELECT id, MAX(rev)
FROM yourTable
GROUP BY id

Это работает в Oracle Sql

-3

Это работает для меня в sqlite3:

SELECT *, MAX(rev) FROM t1 GROUP BY id

С *, вы получаете дублированный столбец rev, но это не так много проблемы.

-3
SELECT * FROM t1 ORDER BY rev DESC LIMIT 1;

Ещё вопросы

Сообщество Overcoder
Наверх
Меню