Как выбрать N-ю строку в таблице базы данных SQL?
Я заинтересован в изучении некоторых (в идеале) агностических способов выбора базы данных nth строка из таблицы базы данных. Было бы также интересно посмотреть, как это может быть достигнуто с помощью встроенных функций следующие базы данных:
- SQL Server
- MySQL
- PostgreSQL
- SQLite
- Оракул
в настоящее время я делаю что-то вроде следующего в SQL Server 2005, но я бы будьте заинтересованы в том, чтобы увидеть другие более агностические подходы:
WITH Ordered AS (
SELECT ROW_NUMBER() OVER (ORDER BY OrderID) AS RowNumber, OrderID, OrderDate
FROM Orders)
SELECT *
FROM Ordered
WHERE RowNumber = 1000000
кредит для вышеуказанного SQL:Firoz Ансари блог
обновление: посмотреть ответ Троэльса Арвина относительно стандарта SQL. Троэльс, у вас есть какие-нибудь ссылки, которые мы можем привести?
29 ответов:
есть способы сделать это в дополнительных частях стандарта, но многие базы данных поддерживают свой собственный способ сделать это.
действительно хороший сайт, который говорит об этом и других вещах http://troels.arvin.dk/db/rdbms/#select-limit.
в принципе, PostgreSQL и MySQL поддерживает нестандартное:
SELECT... LIMIT y OFFSET xOracle, DB2 и MSSQL поддерживают стандартные оконные функции:
SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY key ASC) AS rownumber, columns FROM tablename ) AS foo WHERE rownumber <= n(который я только что скопировал из сайт связан выше, так как я никогда не использую эти DBs)
обновление: начиная с PostgreSQL 8.4 поддерживаются стандартные оконные функции, поэтому ожидайте, что второй пример будет работать и для PostgreSQL.
The
LIMIT/OFFSETсинтаксис в PostgreSQL - это:SELECT * FROM mytable ORDER BY somefield LIMIT 1 OFFSET 20;в этом примере выбирается 21-я строка.
OFFSET 20говорит Postgres пропустить первые 20 записей. Если вы не укажетеORDER BYпункт, нет никакой гарантии, что запись вы получите обратно, что редко бывает полезно.по-видимому, стандарт SQL молчит о предельной проблеме за пределами сумасшедших оконных функций, поэтому все реализуют ее по-разному.
Я не уверен ни в одном из остальных, но я знаю, что SQLite и MySQL не имеют никакого порядка строк "по умолчанию". В этих двух диалектах, по крайней мере, следующий фрагмент захватывает 15-ю запись из таблицы the_table, сортируя по дате/времени ее добавления:
SELECT * FROM the_table ORDER BY added DESC LIMIT 1,15(конечно, вам нужно будет добавить поле DATETIME и установить его на дату/время добавления этой записи...)
SQL 2005 и выше имеет эту встроенную функцию. Используйте функцию ROW_NUMBER (). Он отлично подходит для веб-страниц с > стиль просмотра:
синтаксис:
SELECT * FROM ( SELECT ROW_NUMBER () OVER (ORDER BY MyColumnToOrderBy) AS RowNum, * FROM Table_1 ) sub WHERE RowNum = 23
Я подозреваю, что это дико неэффективно, но это довольно простой подход, который работал на небольшом наборе данных, который я пробовал.
select top 1 field from table where field in (select top 5 field from table order by field asc) order by field descЭто будет получить 5-й элемент, изменить второй верхний номер, чтобы получить другой N-й элемент
только SQL server (я думаю), но должен работать на более старых версиях, которые не поддерживают ROW_NUMBER ().
проверьте его на SQL Server:
Select top 10 * From emp EXCEPT Select top 9 * From empЭто даст вам 10-ю строку таблицы emp!
вопреки тому, что утверждают некоторые ответы, стандарт SQL не молчит по этому вопросу.
начиная с SQL: 2003, вы можете использовать "оконные функции" для пропуска строк и ограничения результирующих наборов.
и в SQL: 2008 был добавлен несколько более простой подход, используя
OFFSET skip ROWS FETCH FIRST n ROWS ONLYлично я не думаю, что добавление SQL:2008 действительно было необходимо, поэтому, если бы я был ISO, я бы сохранил его из уже довольно большого стандарта.
когда мы работали в MSSQL 2000, мы делали то, что мы называли "тройной флип":
редактировать
DECLARE @InnerPageSize int DECLARE @OuterPageSize int DECLARE @Count int SELECT @Count = COUNT(<column>) FROM <TABLE> SET @InnerPageSize = @PageNum * @PageSize SET @OuterPageSize = @Count - ((@PageNum - 1) * @PageSize) IF (@OuterPageSize < 0) SET @OuterPageSize = 0 ELSE IF (@OuterPageSize > @PageSize) SET @OuterPageSize = @PageSize DECLARE @sql NVARCHAR(8000) SET @sql = 'SELECT * FROM ( SELECT TOP ' + CAST(@OuterPageSize AS nvarchar(5)) + ' * FROM ( SELECT TOP ' + CAST(@InnerPageSize AS nvarchar(5)) + ' * FROM <TABLE> ORDER BY <column> ASC ) AS t1 ORDER BY <column> DESC ) AS t2 ORDER BY <column> ASC' PRINT @sql EXECUTE sp_executesql @sqlЭто было не элегантно, и это было не быстро, но это сработало.
SQL SERVER
выберите n-ю запись сверху
SELECT * FROM ( SELECT ID, NAME, ROW_NUMBER() OVER(ORDER BY ID) AS ROW FROM TABLE ) AS TMP WHERE ROW = nвыберите n-ю запись снизу
SELECT * FROM ( SELECT ID, NAME, ROW_NUMBER() OVER(ORDER BY ID DESC) AS ROW FROM TABLE ) AS TMP WHERE ROW = n
вот быстрое решение вашей путаницы.
SELECT * FROM table ORDER BY `id` DESC LIMIT N, 1Это очень распространенный вопрос во время интервью, и это очень простой ответ на него.
далее, если вам нужна сумма, идентификатор или какой-то числовой порядок сортировки, чем u может пойти для функции CAST в MySQL.
SELECT DISTINCT (`amount`) FROM cart ORDER BY CAST( `amount` AS SIGNED ) DESC LIMIT 4 , 1здесь, заполнив N = 4, Вы сможете получить пятую последнюю запись Самая высокая сумма из таблицы корзины. Вы можете подогнать свое поле и имя таблицы и придумать решение.
ограничение n, 1 не работает в MS SQL Server. Я думаю, что это единственная крупная база данных, которая не поддерживает этот синтаксис. Справедливости ради, это не является частью стандарта SQL, хотя он настолько широко поддерживается, что он должен быть. Во всем, кроме SQL server LIMIT отлично работает. Для SQL server я не смог найти элегантное решение.
вот общая версия sproc, которую я недавно написал для Oracle, которая позволяет динамическую подкачку / сортировку-HTH
-- p_LowerBound = first row # in the returned set; if second page of 10 rows, -- this would be 11 (-1 for unbounded/not set) -- p_UpperBound = last row # in the returned set; if second page of 10 rows, -- this would be 20 (-1 for unbounded/not set) OPEN o_Cursor FOR SELECT * FROM ( SELECT Column1, Column2 rownum AS rn FROM ( SELECT tbl.Column1, tbl.column2 FROM MyTable tbl WHERE tbl.Column1 = p_PKParam OR tbl.Column1 = -1 ORDER BY DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 1, Column1, 'X'),'X'), DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 1, Column1, 'X'),'X') DESC, DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate), DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate) DESC )) WHERE (rn >= p_lowerBound OR p_lowerBound = -1) AND (rn <= p_upperBound OR p_upperBound = -1);
но на самом деле, разве все это не просто салонные трюки для хорошего дизайна базы данных в первую очередь? Несколько раз мне нужна была такая функциональность, как это было для простого запроса, чтобы сделать быстрый отчет. Для любой реальной работы, используя трюки, как эти приглашает неприятности. Если выбор конкретной строки необходим, то просто иметь столбец с последовательным значением и сделать с ним.
например, если вы хотите выбрать каждую 10-ю строку в MSSQL, вы можете использовать;
SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY ColumnName1 ASC) AS rownumber, ColumnName1, ColumnName2 FROM TableName ) AS foo WHERE rownumber % 10 = 0просто возьмите мод и изменить номер 10 здесь любое число, которое вы хотите.
в Sybase SQL Anywhere:
SELECT TOP 1 START AT n * from table ORDER BY whateverНе забывайте порядок ПО или это бессмысленно.
для SQL Server общий способ перейти по номеру строки как таковой: Установите ROWCOUNT @row --@row = номер строки, над которой вы хотите работать.
Например:
set rowcount 20 --устанавливает строку в 20-ю строку
выберите мясо, сыр из dbo.сэндвич --выберите столбцы из таблицы в 20-й строке
задать количество строк 0-задает количество строк для всех строк
это вернет информацию 20-й строки. Будьте уверены, чтобы поставить в параметр rowcount 0 потом.
Я знаю noobish, но я SQL noob, и я использовал его, так что я могу сказать?
T-SQL-выбор N-го номера записи из таблицы
select * from (select row_number() over (order by Rand() desc) as Rno,* from TableName) T where T.Rno = RecordNumber Where RecordNumber --> Record Number to Select TableName --> To be Replaced with your Table Nameнапример, чтобы выбрать 5-ю запись из таблицы сотрудника, ваш запрос должен быть
select * from (select row_number() over (order by Rand() desc) as Rno,* from Employee) T where T.Rno = 5
SELECT top 1 * FROM table_name WHERE column_name IN ( SELECT top N column_name FROM TABLE ORDER BY column_name ) ORDER BY column_name DESCЯ написал этот запрос для поиска N-й строки. Пример с этим запросом будет
SELECT top 1 * FROM Employee WHERE emp_id IN ( SELECT top 7 emp_id FROM Employee ORDER BY emp_id ) ORDER BY emp_id DESC
невероятно, что вы можете найти SQL-движок, выполняющий этот...
WITH sentence AS (SELECT stuff, row = ROW_NUMBER() OVER (ORDER BY Id) FROM SentenceType ) SELECT sen.stuff FROM sentence sen WHERE sen.row = (ABS(CHECKSUM(NEWID())) % 100) + 1
ничего особенного, никаких специальных функций, если вы используете Caché, как я...
SELECT TOP 1 * FROM ( SELECT TOP n * FROM <table> ORDER BY ID Desc ) ORDER BY ID ASCучитывая, что у вас есть столбец ID или столбец datestamp, которому вы можете доверять.
вот как я бы сделал это в DB2 SQL, я считаю, что RRN (относительный номер записи) хранится в таблице O / S;
SELECT * FROM ( SELECT RRN(FOO) AS RRN, FOO.* FROM FOO ORDER BY RRN(FOO)) BAR WHERE BAR.RRN = recordnumber
select * from (select * from ordered order by order_id limit 100) x order by x.order_id desc limit 1;Сначала выберите верхние 100 строк, упорядочив их по возрастанию, а затем выберите последнюю строку, упорядочив ее по убыванию и ограничьте до 1. Однако это очень дорогое заявление, поскольку оно дважды обращается к данным.
Мне кажется, что для эффективности вам нужно 1) сгенерировать случайное число между 0 и одним меньше, чем количество записей базы данных, и 2) иметь возможность выбрать строку в этой позиции. К сожалению, разные базы данных имеют разные генераторы случайных чисел и разные способы выбора строки в позиции в результирующем наборе - обычно вы указываете, сколько строк пропустить и сколько строк вы хотите, но это делается по-разному для разных баз данных. Вот то, что работает для меня в SQLite:
select * from Table limit abs(random()) % (select count(*) from Words), 1;Это зависит от возможности использовать подзапрос в предложении limit (который в SQLite является LIMIT
, ) выбор количества записей в таблице должен быть особенно эффективным, являясь частью метаданных базы данных, но это зависит от реализации базы данных. Кроме того, я не знаю, действительно ли запрос построит результирующий набор перед получением N-й записи, но я надеюсь, что это не нужно. Обратите внимание, что я не указание предложения "order by". Возможно, лучше "заказать" что - то вроде первичного ключа, который будет иметь индекс-получение N-й записи из индекса может быть быстрее, если база данных не может получить N-ю запись из самой базы данных без построения результирующего набора.
в Oracle 12c, вы можете использовать С
ORDER BYнапример, чтобы получить 3-ю запись сверху:
SELECT * FROM sometable ORDER BY column_name OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY;
для SQL server следующая строка возвращает первую строку из таблицы giving.
declare @rowNumber int = 1; select TOP(@rowNumber) * from [dbo].[someTable]; EXCEPT select TOP(@rowNumber - 1) * from [dbo].[someTable];вы можете перебирать значения с помощью чего-то вроде этого:
WHILE @constVar > 0 BEGIN declare @rowNumber int = @consVar; select TOP(@rowNumber) * from [dbo].[someTable]; EXCEPT select TOP(@rowNumber - 1) * from [dbo].[someTable]; SET @constVar = @constVar - 1; END;
Comments