Using rownum in oracle SQL statement in combination with order by clause - sql

Which of the following two SQL statements will return the desired result set (i.e. the ten rows with Status=0 and the highest StartTimes)?
Will both statements always return the same result set (StartTime is unique)?
SELECT *
FROM MyTable
WHERE Status=0
AND ROWNUM <= 10
ORDER BY StartTime DESC
SELECT *
FROM (
SELECT *
FROM MyTable
WHERE Status=0
ORDER BY StartTime DESC
)
WHERE ROWNUM <= 10
Background
My DBAdmin told me that the first statement will first limit the table to 10 rows and than order those random rows by StartTime, which is definitly not what I want.
From what I learned in that answer, the order by clause of the second statement is redundant and could be removed by an optimizer, which is also not what I want.
I asked a similar question concering the limit clause in a query to a SQLite database and am interested in understanding any differences to the above statements (using limit Vs rownum) used with an oracle db.

Your Second Query will work
Because in the first ,the first ten rows with Status 0 are selected and then the order by is done in that case the first ten rows fetched need not be in the highest order

Related

Use of rownum in batching the data from oracle

Recently i was using the rownum in the sql query to fetch the data from oracle db in batch of 1000 records. for example 1 to 1000, 1001 to 2000 etc.
Note:
I have about a million records in the table
I am querying the table to get records 1000 at a time
I used the below query
SELECT NAME FROM (
SELECT NAME, ROWNUM RN
FROM employee
) WHERE RN >= ? AND RN <= ?
to fetch the data but stuck in strange issue.
The records in the db are unique but after complete execution I end up getting some duplicate record.
Is there any issue with the query? Is rownum causing issue? Is it possible that the record fetched in first batch of 1000 is also coming in the next subsequent batch?
You can't trust the order of records returned from a query without an explicit order by clause. If the inner query doesn't return values in the same order in each execution, you may get the same row in two separate executions, and thus duplicates in the overall execution.
Is there any issue with the query? Is rownum causing issue?
Yes, Oracle does not guarantee you that a common ordering will be used each time you see the output from a query. So ROWNUM, without an ORDER BY is not useful.Try these options.
In 11g use row_number with an order by, in Oracle 12c use FETCH..FIRST syntax, you should have a primary key / unique key column for this to work.
SELECT NAME
FROM (SELECT NAME,
row_number()
OVER(
ORDER BY primary_key_col ) rn
FROM employee)
WHERE rn >=?
AND rn <=? ;
SELECT NAME
FROM employee
ORDER BY primary_key_col offset ? FETCH first ? rows only;

Select rows randomly without changing the order in sql query

I searched everywhere to find an SQL query to select rows randomly without changing the order. Almost everyone uses something like this:
SELECT * FROM table WHERE type = 1 ORDER BY RAND() LIMIT 25
But above query changes the order. I need a query which selects randomly among the rows but doesn't changes the order, cause every record has a date also.
Select the random rows and then re-order them:
select t.*
from (select *
from table t
where type = 1
order by rand()
limit 25
) t
order by datecol;
In SQL, if you want rows in a particular order, you need to use an explicit order by clause. You should never depend on the ordering of results with no order by. SQL does not guarantee the ordering. MySQL does not guarantee the ordering, unless the query has an order by.

Oracle Row fetch within limit

I want to fetch data between 10000 to 20000 rownum i have made this query
SELECT xml_to_string(XMLRECORD) FROM TABLENAME WHERE ROWNUM >10000 AND ROWNUM<=20000
but above query is not working but when i change query to
SELECT xml_to_string(XMLRECORD) FROM TABLENAME WHERE ROWNUM >0 AND ROWNUM<=20000
it works fine
what am i missing..?
Try this:
SELECT xml_to_string(XMLRECORD) FROM (select t.*, rownum rw from TABLENAME t)
WHERE rw>10000 AND rw<=20000
Rownum is calculated when Oracle retrieves the result of the query. That's why a query select * from some_table where rownum > 1 never returns anything.
In addition, without ORDER BY it doesn't make sense to get rows between 10000 and 20000. You might as well get the first 10000 (as rows are unsorted the result is unpredictable - any row can be the first).
From Oracle documentation:
For each row returned by a query, the ROWNUM pseudocolumn returns a
number indicating the order in which Oracle selects the row from a
table or set of joined rows. The first row selected has a ROWNUM of 1,
the second has 2, and so on.
Conditions testing for ROWNUM values greater than a positive integer
are always false. For example, this query returns no rows:
SELECT *
FROM employees
WHERE ROWNUM > 1;
The first row fetched is assigned a ROWNUM of 1 and makes the
condition false. The second row to be fetched is now the first row and
is also assigned a ROWNUM of 1 and makes the condition false. All rows
subsequently fail to satisfy the condition, so no rows are returned.
rownum doesnot stay in any table It generates run time so when ever you run any sql statement then only for that time rownum will generate so you can't expect that you can use row num in between close.

fetching data using rownum in oracle

I have a query in oracle to fetch data from table using rownum but i didn't get any data.
My query is like this :
select * from table-name where rownum<5
is this is a wrong query to fetch data whose row number is less than 5.
when i used query like :
select * from table-name where rownum<=4
than it will gives a result record.
My question is what is wrong here with ?
Is this is syntax error or anything else??..
rownum is a pseudo column that counts rows in the result set after the where clause has been applied.
SELECT table_name
FROM user_tables
WHERE rownum > 2;
TABLE_NAME
------------------------------
0 rows selected
However, this query will always return zero rows, regardless of the number of rows in the table.
To explain this behaviour, we need to understand how Oracle processes ROWNUM. When assigning ROWNUM to a row, Oracle starts at 1 and only increments the value when a row is selected; that is, when all conditions in the WHERE clause are met. Since our condition requires that ROWNUM is greater than 2, no rows are selected and ROWNUM is never incremented beyond 1.
http://blog.lishman.com/2008/03/rownum.html
another stackoverflow link
Edited
this paragraph i find on oracle website which is much better
Conditions testing for ROWNUM values greater than a positive integer are always false. For example, this query returns no rows:
SELECT * FROM employees
WHERE ROWNUM > 1;
The first row fetched is assigned a ROWNUM of 1 and makes the condition false. The second row to be fetched is now the first row and is also assigned a ROWNUM of 1 and makes the condition false. All rows subsequently fail to satisfy the condition, so no rows are returned.
You can also use ROWNUM to assign unique values to each row of a table, as in this example:
Syntax seems correct to me.
However ROWNUM is calculated on result rows for example:
SELECT * FROM TABLE_NAME WHERE ROWNUM < 10 ORDER BY TABLE_FIELD ASC;
and
SELECT * FROM TABLE_NAME WHERE ROWNUM < 10 ORDER BY TABLE_FIELD DESC;
Will give you different results.
Each time a query is executed, for each tuple, Oracle assigns a ROWNUM which is scopet to that only query.
What are you trying to accomplish ?
Since for the reasons rahularyansharma mentions, rownum based queries won't always function the way you might expect, a way around this is to do something like
SELECT * from (SELECT rownum AS rn, TABLE_NAME.* FROM TABLE_NAME)
where rn > 5;
However, be aware that this will be a fairly inefficient operation when operating over large datasets.

Paging with Oracle and sql server and generic paging method

I want to implement paging in a gridview or in an html table which I will fill using ajax. How should I write queries to support paging? For example if pagesize is 20 and when the user clicks page 3, rows between 41 and 60 must be shown on table. At first I can get all records and put them into cache but I think this is the wrong way. Because data can be very huge and data can be change from other sessions. so how can I implement this? Is there any generic way ( for all databases ) ?
As others have suggested, you can use rownum in Oracle. It's a little tricky though and you have to nest your query twice.
For example, to paginate the query
select first_name from some_table order by first_name
you need to nest it like this
select first_name from
(select rownum as rn, first_name from
(select first_name from some_table order by first_name)
) where rn > 100 and rn <= 200
The reason for this is that rownum is determined after the where clause and before the order by clause. To see what I mean, you can query
select rownum,first_name from some_table order by first_name
and you might get
4 Diane
2 Norm
3 Sam
1 Woody
That's because oracle evaluates the where clause (none in this case), then assigns rownums, then sorts the results by first_name. You have to nest the query so it uses the rownum assigned after the rows have been sorted.
The second nesting has to do with how rownum is treated in a where condition. Basically, if you query "where rownum > 100" then you get no results. It's a chicken and egg thing where it can't return any rows until it finds rownum > 100, but since it's not returning any rows it never increments rownum, so it never counts to 100. Ugh. The second level of nesting solves this. Note it must alias the rownum column at this point.
Lastly, your order by clause must make the query deterministic. For example, if you have John Doe and John Smith, and you order by first name only, then the two can switch places from one execution of the query to the next.
There are articles here http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html
and here http://www.oracle.com/technology/oramag/oracle/07-jan/o17asktom.html. Now that I see how long my post is, I probably should have just posted those links...
Unfortunately, the methods for restricting the range of rows returned by a query vary from one DBMS to another: Oracle uses ROWNUM (see ocdecio's answer), but ROWNUM won't work in SQL Server.
Perhaps you can encapsulate these differences with a function that takes a given SQL statement and first and last row numbers and generates the appropriate paginatd SQL for the target DBMS - i.e. something like:
sql = paginated ('select empno, ename from emp where job = ?', 101, 150)
which would return
'select * from (select v.*, ROWNUM rn from ('
+ theSql
+ ') v where rownum < 150) where rn >= 101'
for Oracle and something else for SQL Server.
However, note that the Oracle solution is adding a new column RN to the results that you'll need to deal with.
I believe that both have a ROWNUM analytic Function. Use that and you'll be identical.
In Oracle it is here
ROW_NUMBER
Yep, just verified that ROW_NUMBER is the same function in both.
"Because...data can be change from other sessions."
What do you want to happen for this ?
For example, user gets the 'latest' ten rows at 10:30.
At 10:31, 3 new rows are added (so those ten being view by the user are no longer the latest).
At 10:32, the user requests then 'next' ten entries.
Do you want that new set to include those three that have been bumped from 8/9/10 down to 11/12/13 ?
If not, in Oracle you can select the data as it was at 10:30
SELECT * FROM table_1 as of timestamp (timestamp '2009-01-29 10:30:00');
You still need the row_number logic, eg
select * from
(SELECT a.*, row_number() over (order by hire_date) rn
FROM hr.employees as of timestamp (timestamp '2009-01-29 10:30:00') a)
where rn between 10 and 19
select *
from ( select /*+ FIRST_ROWS(n) */ a.*,
ROWNUM rnum
from ( your_query_goes_here,
with order by ) a
where ROWNUM <=
:MAX_ROW_TO_FETCH )
where rnum >= :MIN_ROW_TO_FETCH;
Step 1: your query with order by
Step 2: select a.*, ROWNUM rnum from ()a where ROWNUM <=:MAX_ROW_TO_FETCH
Step 3: select * from ( ) where rnum >= :MIN_ROW_TO_FETCH;
put 1 in 2 and 2 in 3
If the expected data set is huge, I'd recommend to create a temp table, a view or a snapshot (materialized view) to store the query results + a row number retrieved either using ROWNUM or ROW_NUMBER analytic function. After that you can simply query this temp storage using row number ranges.
Basically, you need to separate the actual data fetch from the paging.
There is no uniform way to ensure paging across various RDBMS products. Oracle gives you rownum which you can use in where clause like:
where rownum < 1000
SQL Server gives you row_id( ) function which can be used similar to Oracle's rownum. However, row_id( ) isn't available before SQL Server 2005.