Есть ли хороший способ в MySQL для репликации функции SQL Server ROW_NUMBER()
?
Например:
SELECT
col1, col2,
ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col3 DESC) AS intRow
FROM Table1
Тогда я мог бы, например, добавить условие, ограничивающее intRow
1, чтобы получить одну строку с самым высоким значением col3
для каждой (col1, col2)
пары.
greatest-n-per-group
чтобы вести вас к подобным вопросам.Sql-Server
тег, так как это был самый высокий голосующий элемент в комбинированном поиске тегов, но он не имеет отношения к SQL Server.Ответы:
Это групповой максимум , один из наиболее часто задаваемых вопросов SQL (поскольку кажется, что это должно быть легко, но на самом деле это не так).
Я часто пухленький для нулевого самостоятельного соединения:
«Получить строки в таблице, для которых нет другой строки с совпадающими col1, col2 имеет более высокое col3». (Вы заметите, что это и большинство других решений с групповым максимумом будут возвращать несколько строк, если несколько строк имеют одинаковые col1, col2, col3. Если это проблема, вам может потребоваться некоторая постобработка.)
источник
SELECT t1.id FROM test t1 LEFT JOIN test t2 ON t1.id>t2.id WHERE t2.id IS NULL;
не требует лиn*n/2 + n/2
сравнение IS NULL для поиска одной строки? Происходят ли какие-либо оптимизации, которых я не вижу? Я пытался задать аналогичный вопрос Биллу в другой ветке, но он, похоже, проигнорировал его.SELECT t0.col3 FROM table AS t0 WHERE NOT EXISTS (select 1 from table AS t1 ON t0.col1=t1.col1 AND t0.col2=t1.col2 AND t1.col3>t0.col3)
В MySQL нет функции ранжирования. Самое близкое, что вы можете получить, это использовать переменную:
Да. Если бы это был Oracle, вы могли бы использовать функцию LEAD для достижения следующего значения. К счастью, Quassnoi охватывает логику для того, что вам нужно реализовать в MySQL .
источник
SELECT @row_num:=@row_num+1 AS row_number, t.id FROM (SELECT * FROM table1 WHERE col = 264 ORDER BY id) t, (SELECT @row_num:=0) var;
Я всегда заканчиваю тем, что следую за этим образцом. Учитывая эту таблицу:
Вы можете получить этот результат:
Запустив этот запрос, для которого не нужно определять переменную:
Надеюсь, это поможет!
источник
<
,>
,<=
,>=
ручка CHAR и типы данных VARCHAR на алфавитном порядке; Я ожидаю, это именно то, что вы ищете.row_numbers <= 2
Огромное спасибо за этот ответ, Мости, это прекрасно!источник
Посмотрите эту статью, в ней показано, как имитировать SQL ROW_NUMBER () с разделом в MySQL. Я столкнулся с тем же сценарием в реализации WordPress. Мне нужно было ROW_NUMBER (), и его там не было.
http://www.explodybits.com/2011/11/mysql-row-number/
Пример в статье использует один раздел по полю. Для разделения на дополнительные поля вы можете сделать что-то вроде этого:
Использование concat_ws обрабатывает нуль. Я проверил это на 3 полях, используя int, date и varchar. Надеюсь это поможет. Проверьте статью, поскольку это разбивает этот запрос и объясняет это.
источник
limit 18446744073709551615
кorder by
предложению force .concat_ws
с пустой строкой''
опасноconcat_ws('',12,3) = concat_ws('',1,23)
. Лучше использовать какой-то разделитель'_'
или использовать решение @Kenneth Xu.Кроме того,
MySQL 8.0.0
вы можете использовать оконные функции.1.4 Что нового в MySQL 8.0 :
ROW_NUMBER () over_clause :
Демо-версия:
DBFiddle Demo
источник
Я также проголосовал бы за решение Моста Мостачо с незначительными изменениями в его коде запроса:
Который даст тот же результат:
для стола:
С той лишь разницей, что запрос не использует JOIN и GROUP BY, полагаясь на вложенный выбор.
источник
Я бы определил функцию:
тогда я мог бы сделать:
Теперь у вас нет подзапроса, который вы не можете иметь в представлениях.
источник
запрос для row_number в MySQL
источник
В MySQL нет такой функции
rownum
,row_num()
как наоборот, как показано ниже:источник
Решение, которое я нашел, чтобы работать лучше всего, использовало подобный подзапрос:
Столбцы PARTITION BY просто сравниваются с '=' и разделяются символом AND. Столбцы ORDER BY будут сравниваться с '<' или '>' и разделяться OR.
Я обнаружил, что это очень гибко, даже если это немного дорого.
источник
Функциональность номера не может быть воспроизведена. Вы можете получить ожидаемые результаты, но, скорее всего, на каком-то этапе вы будете разочарованы. Вот что говорит документация mysql:
С уважением, Георгий.
источник
MariaDB 10.2 реализует «оконные функции», включая RANK (), ROW_NUMBER () и несколько других вещей:
https://mariadb.com/kb/en/mariadb/window-functions/
Основываясь на выступлении в Percona Live в этом месяце, они достаточно хорошо оптимизированы.
Синтаксис идентичен коду в вопросе.
источник
Я не вижу простого ответа, охватывающего часть "PARTITION BY", так что вот мой:
В этом простом примере я поставил только одну, но у вас может быть несколько частей "PARTITION BY"
источник
Немного поздно, но также может помочь тому, кто ищет ответы ...
Между row / row_number example - рекурсивный запрос, который можно использовать в любом SQL:
источник
Это позволяет выполнять те же функции, что и ROW_NUMBER () AND PARTITION BY, в MySQL.
источник
Также немного поздно, но сегодня у меня возникла такая же потребность, поэтому я выполнил поиск в Google, и, наконец, простой общий подход был найден здесь в статье Пинала Дейва http://blog.sqlauthority.com/2014/03/09/mysql-reset-row -количество-для-каждого-группового раздела за строкой-числом /
Я хотел сосредоточиться на первоначальном вопросе Пола (это была и моя проблема), поэтому я суммирую свое решение в качестве рабочего примера.
Поскольку мы хотим разбить на два столбца, я бы создал переменную SET во время итерации, чтобы определить, была ли запущена новая группа.
3 означает в первом параметре MAKE_SET, что я хочу оба значения в SET (3 = 1 | 2). Конечно, если у нас нет двух или более столбцов, составляющих группы, мы можем исключить операцию MAKE_SET. Конструкция точно такая же. Это работает для меня как требуется. Большое спасибо Пиналу Дейву за его наглядную демонстрацию.
источник
ORDER BY
в подзапросе может быть проигнорировано (см. Mariadb.com/kb/en/mariadb/… ). Предлагаемое решение этого - добавитьLIMIT 18446744073709551615
к подзапросу, который вызывает сортировку. Однако это может вызвать проблемы с производительностью и не подходит для действительно ужасных огромных таблиц :)Это также может быть решением:
источник
MySQL поддерживает ROW_NUMBER () начиная с версии 8.0+ .
Если вы используете MySQL 8.0 или более позднюю версию, проверьте функцию ROW_NUMBER (). В противном случае вы должны эмулировать функцию ROW_NUMBER ().
Row_number () - это функция ранжирования, которая возвращает порядковый номер строки, начиная с 1 для первой строки.
для старой версии,
источник
Важное замечание: Пожалуйста, рассмотрите возможность обновления до MySQL 8+ и использования определенной и документированной функции ROW_NUMBER (), а также откажитесь от старых хаков, связанных с древней версией MySQL с ограниченной функциональностью.
Теперь вот один из тех хаков:
Ответы здесь, которые используют переменные в запросе, в основном / все, кажется, игнорируют тот факт, что документация говорит (перефразировать):
Таким образом, есть риск, что они будут выдавать неправильный ответ, потому что они обычно делают
Если они когда-либо оцениваются снизу вверх, номер строки перестанет работать (без разделов)
Поэтому нам нужно использовать что-то с гарантированным порядком исполнения. Введите СЛУЧАЙ КОГДА:
Как и в общих чертах, порядок назначения prevcol важен - его нужно сравнить со значением текущей строки, прежде чем мы присвоим ему значение из текущей строки (в противном случае это будет значение столбца текущей строки, а не значение столбца предыдущей строки) ,
Вот как это сочетается:
Первый КОГДА оценивается. Если col этой строки совпадает с col предыдущей строки, то @r увеличивается и возвращается из CASE. Эти возвращаемые светодиодные значения хранятся в @r. Особенностью MySQL является то, что присваивание возвращает новое значение того, что назначено в @r, в строки результатов.
Для первой строки в наборе результатов @prevcol имеет значение null (в подзапросе оно инициализируется значением null), поэтому этот предикат имеет значение false. Этот первый предикат также возвращает false при каждом изменении col (текущая строка отличается от предыдущей строки). Это заставляет второй КОГДА быть оцененным.
Второй предикат WHEN всегда ложен, и он существует исключительно для назначения нового значения @prevcol. Поскольку col этой строки отличается от col предыдущей строки (мы знаем это потому, что если бы это было то же самое, использовался бы первый WHEN), мы должны присвоить новое значение, чтобы сохранить его для тестирования в следующий раз. Поскольку присваивание выполняется, а затем результат присваивания сравнивается с нулем, а все, что приравнивается к нулю, является ложным, этот предикат всегда ложен. Но, по крайней мере, оценив его, он сохранил значение col из этой строки, чтобы его можно было сравнить со значением col следующей строки.
Поскольку второе WHEN имеет значение false, это означает, что в ситуациях, когда столбец, который мы разделяем (col), изменился, это ELSE, который дает новое значение для @r, перезапуская нумерацию с 1
Мы это попадаем в ситуацию, когда это:
Имеет общую форму:
Примечания:
P в pcol означает «раздел», o в ocol означает «порядок» - в общем виде я убрал «prev» из имени переменной, чтобы уменьшить визуальный беспорядок
Скобки вокруг
(@pcolX := colX) = null
важны. Без них вы присваиваете @pcolX значение null, и все перестает работатьЭто компромисс, что результирующий набор должен быть упорядочен также по столбцам разделов, чтобы сравнение предыдущего столбца сработало. Таким образом, вы не можете упорядочить свое числовое число в соответствии с одним столбцом, но ваш набор результатов должен быть упорядочен в другом. Возможно, вы сможете решить эту проблему с помощью подзапросов, но я считаю, что в документах также говорится, что упорядочение подзапросов может игнорироваться, если не используется LIMIT, и это может повлиять производительность
Я не вдавался в подробности после тестирования того, что метод работает, но если есть риск, что предикаты во втором случае будут оптимизированы (что-либо по сравнению с нулем равно null / false, так зачем беспокоиться о выполнении назначения) и не выполняется также останавливается. По моему опыту, этого не происходит, но я с удовольствием приму комментарии и предложу решение, если это может произойти.
Может быть целесообразно привести нулевые значения, которые создают @pcolX, к фактическим типам ваших столбцов в подзапросе, который создает переменные @pcolX, а именно:
select @pcol1 := CAST(null as INT), @pcol2 := CAST(null as DATE)
источник
Это не самое надежное решение - но если вы просто хотите создать секционированный ранг для поля с несколькими значениями, может быть не лишним использовать случай, когда логика содержит столько переменных, сколько вам нужно.
Нечто подобное работало для меня в прошлом:
Надеюсь, что это имеет смысл / помогает!
источник
Эта работа идеально подходит для меня, чтобы создать RowNumber, когда у нас есть более одного столбца. В этом случае два столбца.
источник
источник
источник