Select n number of records from oracle database - sql

I have to select n number of rows from an oracle database from sap using native sql. In open sql the query would be like
select * from myDB where size > 2000 upto n rows.
what I learnt from other posts the equivalent native sql query would be
SELECT * FROM myDB WHERE SIZE > 2000 AND rownum <= 100
is this correct?
Do I need to have rownum as one of the fields in the DB table?

SELECT *
FROM myDB
WHERE SIZE > 2000
AND ROWNUM <= 100
Is a syntactically correct query.
Do I need to have rownum as one of the fields in the DB table?
No, the ROWNUM pseudocolumn assigns, for each row returned by a query, 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.
Note that ROWNUM is applied before any ORDER BY clauses.
So:
SELECT *
FROM myDB
WHERE ROWNUM <= 10
ORDER BY column_name
Will select 10 rows (it could be any 10 rows and not necessarily the 10 rows which are first in the desired ordering) and then will order those 10 rows by the desired column.
If you want to get the rows with the top-N values for a column then you need to apply the ORDER BY first and then restrict the number of rows:
SELECT *
FROM ( SELECT *
FROM myDB
ORDER BY column_name )
WHERE ROWNUM <= 10
If you are using Oracle 12 then they have implemented a new syntax for TOP-N queries:
SELECT *
FROM myDB
ORDER BY column_name
FETCH FIRST 10 ROWS ONLY;

ROWNUM is a pseudocolumn generated by Oracle whenever you perform a SELECT. The assignment of the value to ROWNUM is the last thing done before the query returns a row - thus, the first row emitted by the query is given ROWNUM = 1, the second row emitted by the query is given ROWNUM = 2, and so on. Notice: this means that a statement like the following WILL RETURN NO ROWS:
SELECT *
FROM SOME_TABLE
WHERE ROWNUM >= 2
Why does this return no rows? It's because the first row which would be emitted by the query is always given ROWNUM = 1, and since the query is looking only for rows with ROWNUM >= 2 no rows will be selected because the first ROWNUM value of 1 is applied to the first row emitted.
HOWEVER - if you really want to get all rows EXCEPT the first (or the first 10, or what have you) you can do it like this:
SELECT *
FROM (SELECT *, ROWNUM AS INNER_ROWNUM
FROM SOME_TABLE
WHERE SOMETHING = SOMETHING_ELSE
ORDER BY WHATEVER) i
WHERE i.INNER_ROWNUM IN (1, 2, 3, 5, 7, 11, 13, 17, 19);
Here we use an inner SELECT which gets ALL rows for the given condition (SOMETHING = SOMETHING_ELSE) and assigns the ROWNUM from the INNER query to a computed column named INNER_ROWNUM, which we can then use as a normal column in the outer query.

Use rownum concept it is a pseudo column in oracle by using this concept we can achieve the TOP keyword functionality.
select col1,col2,col3..coln from
(
select rownum rn,e.* from mydb where size>2000
)
where rn>N
Note: Col1 to coln are column names of your table.

Related

Using DBMS_RANDOM.Value function in SQL query for equality comparison - returning multiple records

I am on Oracle 11g and the case is as follows.
I have a select from subquery, like this:
select * from (
select rownum as rn
, 'just testing_' || rownum as just_string
from dual
connect by level <= 20
)
where rn = round(dbms_random.value(1,20))
so the result of subquery is 20 records with numeric column "rn" value from 1 to 20, and I expect to get one record from that subquery by comparing to result of DBMS_RANDOM.value, which I expect to get me an integer value from 1 to 20
However... result os such query tend to vary from no records to multiple records:
If I enclose the DBMS_RANDOM.value function in subquery like this:
select * from (
select rownum as rn
, 'just testing_' || rownum as just_string
from dual
connect by level <= 20
)
where rn = (select round(dbms_random.value(1,20)) from dual)
then it seems to always return one row as expected.
So can anyone explain how the first query works with DBMS_RANDOM.value so that it returns multiple or no rows ?
dbms_random.value gets executed for each row that is returned by your subquery, not just one time. So your first query may return any number of rows between 0 and 20 (last one very, very, ... unlikely). The second query executes dbms_random.value just once, as dual has 1 row, and so it always returns just one row.

How to skip/offset rows in Oracle database?

I am writing a very simple query for an Oracle DB (version 9).
Somehow I can get first 5 rows:
select * from cities where rownum <= 5
But skipping 5 rows returns an empty result:
select * from cities where rownum >= 5
Using:
Oracle SQL Developer
Oracle DB version 9
Why is the second query returning an empty result?
In Oracle Database 12c (release 1) and above, you can do this very simple, for skip 5 rows:
SELECT * FROM T OFFSET 5 ROWS
and for skip 5 rows and take 15 rows:
SELECT * FROM T OFFSET 5 ROWS FETCH NEXT 15 ROWS ONLY
You can use the following query to skip the first not n of rows.
select * from (
select rslts.*, rownum as rec_no from (
<<Query with proper order by (If you don't have proper order by you will see weird results)>>
) rslts
) where rec_no > <<startRowNum - n>>
The above query is similar to pagination query below.
select * from (
select rslts.*, rownum as rec_no from (
<<Query with proper order by (If you don't have proper order by you will see weird results)>>
) rslts where rownum <= <<endRowNum>>
) where rec_no > <<startRowNum>>
Your cities query:
select * from (
select rslts.*, rownum as rec_no from (
select * from cities order by 1
) rslts
) where rec_no > 5 <<startRowNum>>
Note: Assume first column in cities table is unique key
Oracle increments rownum each time it adds a row to the result set. So saying rownum < 5 is fine; as it adds each of the first 5 rows it increments rownum, but then once ruwnum = 5 the WHERE clause stops matching, no more rows are added to the result, and though you don't notice this rownum stops incrementing.
But if you say WHERE rownum > 5 then right off the bat, the WHERE clause doesn't match; and since, say, the first row isn't added to the result set, rownum isn't incremented... so rownum can never reach a value greater than 5 and the WHERE clause can never match.
To get the result you want, you can use row_number() over() in a subquery, like
select *
from (select row_number() over() rn, -- other values
from table
where -- ...)
where rn > 5
Update - As noted by others, this kind of query only makes sense if you can
control the order of the row numbering, so you should really use row_number() over(order bysomething) where something is a useful ordering key in deciding which records are "the first 5 records".
rownum is being increased only when a row is being output, so this type of condition won't work.
In any case, you are not ordering your rows, so what's the point?
Used row_number() over (order by id):
select * from
(select row_number() over (order by id) rn, c.* from countries c)
where rn > 5
Used ROWNUM:
select * from
(select rownum rn, c.* from countries c)
where rn > 5
Important note:
Using alias as countries c instead of countries is required! Without, it gives an error "missing expression"
Even better would be:
select * from mytab sample(5) fetch next 1 rows only;
Sample clause indicates the probability of each row getting picked up in the sampling process. FETCH NEXT clause indicates the number of rows you want to select.
With this code, you can query your table with skip and take.
select * from (
select a.*, rownum rnum from (
select * from cities
) a
) WHERE rnum >= :skip + 1 AND rnum <= :skip + :take
This code works with Oracle 11g. With Oracle 12, there is already a better way to perform this queries with offset and fetch

Oracle SQL Developer function does not work

Please I can't understand why some function is not working in my Oracle sql Developer. I am trying to select row num 2, but Oracle returns an empty row just the headers.
But when I use row num 1, Oracle returns the first row, if I specify row num <= 2, Oracle returns rows 1 and 2. The vice versa doesn't work, row num >=2 by the way FETCH and offset return error
select *
from PAS.TRANSACTION
where msisdn in ('1112684179')
and rownum = 2
order by INSERTION_DATE DESC;
It is not working because: for the first row it is tested against a ROWNUM of 1 and, in this case, ROWNUM = 2 is false and the row is discarded. Since that row was discarded it is not assigned the ROWNUM and instead the next row is tested against that same ROWNUM of 1; the cycle repeats and ROWNUM = 2 is false and the row is discarded. Repeat, ad nauseum and all rows fail the WHERE test and are discarded.
If you want to get the second row then you need to assign every row a ROWNUM within an inline view and then once that has been processed then select the second row.
SELECT * -- Finally, in the outer select get
-- the 2nd row
FROM (
SELECT t.*, -- Second, having ordered the rows
ROWNUM AS rn -- then generate the row numbers
(
select * -- Fisrt, in the inner-most inline
from PAS.TRANSACTION -- view, select the rows you want
where msisdn in ('1112684179') -- and apply the order.
order by INSERTION_DATE DESC
)
)
WHERE rn = 2;
(Also, note that the ROWNUM pseudo-column is generated before the query is ordered - so if you want it to order first and then number based on that ordering then you need to order within an inline view and generate the ROWNUM at the next step - as is done in the example above.)

why we cannot use condition rownum=5 in oracle

I observed that rownum can be used as follows:
1) select * from emp where rownum<5;
2) select * from emp where rownum<=5;
3) select * from emp where rownum=1;
All this queries return expected output. Say table emp has 7 rows then 1st query returns 4 rows, 2nd returns 5 rows ,3rd returns 1 row.
But when I try to use something like:
4) select * from emp where rownum=5;
5) select * from emp where rownum>5;
6) select * from emp where rownum>=5;
7) select * from emp where rownum between 5 and 10;
In all this cases, it returns 0 rows. Why this is so? Is there any specific reason for this?
This is because rownum is a pseudo column and it counts rows in the result set after you apply the where clause.
From the Oracle docs:-
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:
UPDATE my_table
SET column1 = ROWNUM;
You may find these references helpfull:-
Using ROWNUM in Oracle
SQL Query With Row_Number, order by and where clause
You can do something similar like this:
select * from (
select
emp.*,
row_number() over (order by fieldname) as rnum
from emp
) tmp
where
rnum between 5 and 10;

Database agnostic query to select top 1 or top n rows?

I have a table with no PK column. I am not supposed to change that. There is also a numeric column which can be used to order the rows. How do i select the top 1 or top n rows without using any function, ie a database agnostic query ?
I looked at this query, but it does not work for my case -
Can there be a database-agnostic SQL query to fetch top N rows?
Per the thread you linked to, there isn't much of a database agnostic solution:
DB2 -- select * from table order by col fetch first 10 rows only
Informix -- select first 10 * from table order by col
Microsoft SQL Server and Access -- select top 10 * from table order by col
MySQL and PostgreSQL -- select * from table order by col limit 10
Oracle 8i -- select * from (select * from table order by col) where rownum <= 10
http://forums.mysql.com/read.php?60,4515,4678