This question already has an answer here:
SQL (ORACLE): ORDER BY and LIMIT [duplicate]
(1 answer)
Closed 7 years ago.
I want to select 1000 rows at a time using the query:
SELECT * FROM MEMBERID_1M WHERE ROWNUM <1000
How do I get the next set of 1000 rows from this table in a for loop?
I suggest you to use ROW_NUMBER() function like this: (my id is your PK)
SELECT M.*
FROM (
SELECT MEMBERID_1M.*, ROW_NUMBER() OVER (ORDER BY id) As rn
FROM MEMBERID_1M ) M
WHERE
(rn <= 1000)
And for next:
SELECT M.*
FROM (
SELECT MEMBERID_1M.*, ROW_NUMBER() OVER (ORDER BY id) As rn
FROM MEMBERID_1M ) M
WHERE
(rn > 1000) AND (rn <= 2000)
For page :i:
SELECT M.*
FROM (
SELECT MEMBERID_1M.*, ROW_NUMBER() OVER (ORDER BY id) As rn
FROM MEMBERID_1M ) M
WHERE
(rn > :i * 1000) AND (rn <= (:i + 1) * 1000)
Reproducing the answer
There is only a rather convoluted way to do this, which is a real pain with Oracle. They should just implement a LIMIT/OFFSET clause...
The rownum gets assigned after the row has been selected by the where clause, so that a rownum must always start with 1. where rownum > x will always evaluate to false.
Also, rownum gets assigned before sorting is done, so the rownum will not be in the same order as your order by says.
You can get around both problems with a subselect:
select a,b,c, rn from
( select a,b,c, rownum rn from
( select a,b,c from the_table where x = ? order by c)
where rownum < Y)
where rn > X
If you do not need to sort (but only then), you can simplify to
select a,b,c, rn from
( select a,b,c, rownum rn from the_table where rownum < Y )
where rn > X
You should be paging on server side .use this query
and more detail refer this link
http://www.oracle.com/technetwork/issue-archive/2007/07-jan/o17asktom-093877.html
select *
from
( select rownum rnum, a.*
from (SELECT * FROM MEMBERID_1M ) a
where rownum <= :M )
where rnum >= :N;
Related
I need to apply LIMIT and OFFSET to original query (without modifying it) in MSSQL server 2008.
Let's say the original query is:
SELECT * FROM energy_usage
(But it can be any arbitrary SELECT query)
That's what I came up with so far:
1. It does what I need, but the query generates extra column row_number which I don't need.
WITH OrderedTable AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS row_number, * FROM energy_usage
)
SELECT * FROM OrderedTable WHERE row_number BETWEEN 1 AND 10
2. This one doesn't work for some reason and returns the following error.
SELECT real_sql.* FROM (
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS row_number, * FROM (SELECT * FROM energy_usage) as real_sql) as subquery
WHERE row_number BETWEEN 1 AND 10
More common case is:
SELECT real_sql.* FROM (
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS row_number, * FROM (real sql query) as real_sql) as subquery
WHERE row_number BETWEEN {offset} + 1 AND {limit} + {offset}
Error:
The column prefix 'real_sql' does not match with a table name or alias
name used in the query.
Simply do not put it on SELECT list:
WITH OrderedTable AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS row_number, *
FROM energy_usage
)
SELECT col1, col2, col3 FROM OrderedTable WHERE row_number BETWEEN 1 AND 10;
SELECT * is common anti-pattern and should be avoided anyway. Plus ORDER BY (SELECT 1) will not give you guarantee of stable sort between executions.
Second if you need only ten rows use:
SELECT TOP 10 *
FROM energy_usage
ORDER BY ...
Unfortunately you won't get something nice as Selecting all Columns Except One
WITH OrderedTable AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS row_number, *
FROM energy_usage
)
SELECT * EXCEPT row_number FROM OrderedTable WHERE row_number BETWEEN 1 AND 10;
This would solve the problem.
DECLARE #offset INT = 1;
DECLARE #limit INT = 10;
WITH Filtered AS (
SELECT TOP (#offset + #limit) *
FROM energy_usage
ORDER BY 1 ASC
), Results AS (
SELECT TOP (#limit) *
FROM Filtered
ORDER BY 1 DESC
)
SELECT *
FROM Results
ORDER BY 1 ASC;
I got below query from another post which selects 100 rows from every 2000 rows.
Like this: 1-100,2001-2100,4001-4100,6001-6100,8001-8100 and so on.
SELECT * FROM (SELECT t.*,ROWNUM AS rn FROM(SELECT * FROM your_table ORDER BY your_condition) t)WHERE MOD( rn - 1, 2000 ) < 100;
Now I want to select my data exponentially.Such that it will select 100 rows from first 1000 rows, then from next 2000 rows, then from next 4000 rows.
Like this: 1-100,2000-2100,4000-4100,8000-8100,16000-16100 and so on.
The idea is to scan rows with a specific pattern.
You asked this in a comment on your previous question and I answered there...
SELECT *
FROM (
SELECT t.*,
ROWNUM AS rn -- Secondly, assign a row number to the ordered rows
FROM (
SELECT *
FROM your_table
ORDER BY your_condition -- First, order the data
) t
)
WHERE rn - POWER( -- Finally, filter the top 100.
2,
TRUNC( CAST( LOG( 2, CEIL( rn / 1000 ) ) AS NUMBER(20,4) ) )
) * 1000 + 1000 <= 100
This will take the first 100 rows from the groups 1-1000, 1001-3000, 3001-7000, 7001-15000, etc.
Or, to get the rows:
1-100,2000-2100,4000-4100,8000-8100,16000-16100, 32000-32100 and so on.
Then:
WHERE CASE -- Finally, filter the top 100.
WHEN rn <= 2000 THEN rn
ELSE rn - POWER(
2,
TRUNC( CAST( LOG( 2, CEIL( rn / 1000 - 1 ) ) AS NUMBER(20,4) ) )
) * 1000
END <= 100
You could use power function and simple hierarchical query, then join it with your table. Here is example with all_objects view:
with rng as (select 0 num from dual union all
select 1000 * power(2, level) from dual connect by level < 10 )
select *
from (select row_number() over (order by object_name) rn, object_name from all_objects)
join rng on rn between num + 1 and num + 100
From what you describe, you can use logs to define the groups. This is probably close enough to what you want:
select t.*
from (select t.*,
row_number() over (floor(log(2, floor(1 + (seqnum - 1) / 1000) ))
order by col
) as seqnum_2
from (select t.*, row_number() over (order by col) as seqnum
from t
) t
where seqnum_2 <= 100;
The difference from your description is that the first group is 1-999, 1000-1999, and so on.
For example:
My table has 10000 rows. First I will divide it in 5 sets of 2000(k) rows. Then from each set of 2000 rows I will select only top 100(n) rows.
With this approach I am trying to scan some rows of table with a specific pattern.
Assuming you are ordering them 1 - 10000 using some logic and want to output only rows 1-100,2001-2100,4001-4100,etc then you can use the ROWNUM pseudocolumn:
SELECT *
FROM (
SELECT t.*,
ROWNUM AS rn -- Secondly, assign a row number to the ordered rows
FROM (
SELECT *
FROM your_table
ORDER BY your_condition -- First, order the data
) t
)
WHERE MOD( rn - 1, 2000 ) < 100; -- Finally, filter the top 100 per 2000.
Or you could use the ROW_NUMBER() analytic function:
SELECT *
FROM (
SELECT t.*,
ROW_NUMBER() OVER ( ORDER BY your_condition ) AS rn
FROM your_table
)
WHERE MOD( rn - 1, 2000 ) < 100;
Is it possible to increase the set of sample data exponentially. Like 1k, 2k, 4k,8k....and then fetch some rows from these.
Replace the WHERE clause with:
WHERE rn - POWER(
2,
TRUNC( CAST( LOG( 2, CEIL( rn / 1000 ) ) AS NUMBER(20,4) ) )
) * 1000 + 1000 <= 100
This solution uses the analytic ntile() to split the raw data into five buckets. That result set is labelled using the analytic row_number() which provides a filter to produce the final set:
with sq1 as ( select id, col1, ntile(5) over (order by id asc) as quintile
from t23
)
, sq2 as ( select id, col1, quintile
, row_number() over ( partition by quintile order by id asc) as rn
from sq1 )
select *
from sq2
where rn <= 200
order by quintile, rn
/
use partition by and order by with row_number. it will look like following:
row_number()over(partition by partition_column order by order_column)<=100
partition_column will be your condition to divide set.
order_column will be your condition to select top 100.
I am trying to order the records by 3 columns and then select a particular ID and the record before that plus the row after that. Here is my query:
;With Cte As
(
SELECT ROW_NUMBER() Over(Order By Book, PageINT, [IDAuto]) as RowNum, [IdAuto]
FROM CCWiseInstr2
)
Select * From Cte
Where RowNum = (Select RowNum From Cte
Where IdAuto = 211079)
UNION
Select * From Cte
Where RowNum = (Select RowNum - 1 From Cte
Where IdAuto = 211079)
UNION
Select * From Cte
Where RowNum = (Select RowNum + 1 From Cte
Where IdAuto = 211079)
What could the other efficient way to write this query. At the moment the query takes about 336 ms after creating all indexes which looks like a bit higher to me.
Here is the plan for the query:
http://gyazo.com/9a7f1c37d4433665d0949acf03c4561c
Any help is appreciated.
How about this query:
;With Cte As
(
SELECT ROW_NUMBER() Over(Order By Book, PageINT, [IDAuto]) as RowNum, [IdAuto]
FROM CCWiseInstr2
)
Select RowNum, IDAuto From Cte
Where RowNum IN (
Select RowNumber From
(
Select RowNum - 1 as RowNumPrev,
RowNum as RowNum,
RowNum + 1 as RowNumNext
From Cte
Where IdAuto = 211079
) vw unpivot (
RowNumber For
IdAuto IN (RowNumPrev, RowNum, RowNumNext )
) unpw )
Instead of UNION just use UNPIVOT which will convert your columns into rows which you could then use in IN. Let me know how it goes.
You can use the LEAD and LAG functions with SQL Server. Here's a great article on Simple Talk covering all of the options. (Code below is untested)
https://www.simple-talk.com/sql/t-sql-programming/sql-server-2012-window-function-basics/
SELECT
[IdAuto],
LAG([IDAuto], 1) OVER(Order By Book, PageINT, [IDAuto]) AS PreviousSale,
LEAD([IDAuto], 1) OVER(Order By Book, PageINT, [IDAuto]) AS NextSale
FROM
CCWiseInstr2
WHERE [IdAuto] = 211079;
I figure I might just be missing some obvious syntax but what is the sql (oracle) to select the first 10 records, then the next 10, and so on?
I tried using rownum but can seem to get rownum > X and rownum < Y to work.
llcf
There is only a rather convoluted way to do this, which is a real pain with Oracle. They should just implement a LIMIT/OFFSET clause...
The rownum gets assigned after the row has been selected by the where clause, so that a rownum must always start with 1. where rownum > x will always evaluate to false.
Also, rownum gets assigned before sorting is done, so the rownum will not be in the same order as your order by says.
You can get around both problems with a subselect:
select a,b,c, rn from
( select a,b,c, rownum rn from
( select a,b,c from the_table where x = ? order by c)
where rownum < Y)
where rn > X
If you do not need to sort (but only then), you can simplify to
select a,b,c, rn from
( select a,b,c, rownum rn from the_table where rownum < Y )
where rn > X
You could use ROW_NUMBER() function... for example
SELECT *
FROM ( SELECT A.*, ROW_NUMBER( ) OVER (ORDER BY MYFIELD) AS MYROW FROM MYTABLE A )
WHERE MYROW < X
SELECT *
FROM ( SELECT A.*, ROW_NUMBER( ) OVER (ORDER BY MYFIELD) AS MYROW FROM MYTABLE A )
WHERE MYROW BETWEEN X AND Y
SELECT *
FROM ( SELECT A.*, ROW_NUMBER( ) OVER (ORDER BY MYFIELD) AS MYROW FROM MYTABLE A )
WHERE MYROW BETWEEN Y AND Z
You could also select all rows, and only fetch 10 at a time. This works only if you can keep the cursor between the fetches, of course.