oracle sql wih rownum <= - sql

why below query is not giving results if I remove the < sign from query.Because even without < it must match with results?
Query used to get second max id value:
select min(id)
from(
select distinct id
from student
order by id desc
)
where rownum <=2
student id
1
2
3
4

Rownum has a special meaning in Oracle. It is increased with every row, but the optimizer knows that is increasing continuously and all consecutive rows must met the rownum condition. So if you specify rownum = 2 it will never occur since the first row is already rejected.
You can see this very nice if you do an explain plan on your query. It will show something like:
Plan for rownum <=:
COUNT STOPKEY
Plan for rownum =:
FILTER

A ROWNUM value is not assigned permanently to a row (this is a common misconception). A row in a table does not have a number; you cannot ask for row 2 or 3 from a table
click Here for more Info.
This is from the link provided:
Also confusing to many people is when a ROWNUM value is actually assigned. A ROWNUM value is assigned to a row after it passes the predicate phase of the query but before the query does any sorting or aggregation. Also, a ROWNUM value is incremented only after it is assigned, which is why the following query will never return a row:
select *
from t
where ROWNUM > 1;
Because ROWNUM > 1 is not true for the first row, ROWNUM does not advance to 2. Hence, no ROWNUM value ever gets to be greater than 1. Consider a query with this structure:
select ..., ROWNUM
from t
where <where clause>
group by <columns>
having <having clause>
order by <columns>;

I think this is the query you are looking for:
select id
from (select distinct id
from student
order by id desc
) t
where rownum <= 2;
Oracle processes the rownum before the order by, so you need a subquery to get the first two rows. The min() was forcing an aggregation that returned only one result, but before the rownum was applied.
If you actually want only the second value, you need an additional layer of subqueries:
select min(id)
from (select id
from (select distinct id
from student
order by id desc
) t
where rownum <= 2
) t;
However, I would do:
select id
from (select id, dense_rank() over (order by id) as seqnum
from student
) t
where seqnum = 2;

Order asc instead of desc
select id from student where rownum <=2 order by id asc;

Why not just use
select id
from ( select distinct id
, row_number() over (order by id desc) x
from student
)
where x = 2
Or even really bad. Getting the count and index :)
select id
from ( select id
, row_number() over (order by id desc) idx
, sum(1) over (order by null) cnt
from student
group
by id
)
where idx = cnt - 1 -- get the pre-last
Or
where idx = cnt - 2 -- get the 2nd-last
Or
where idx = 3 -- get the 3rd

Try this
SELECT *
FROM (
SELECT id, row_number() over (order by id asc) row_num
FROM student
) AS T
WHERE row_num = 2 -- or 3 ... n
ROW_NUMBER

Related

Select rows based on distinct values of nested field in BigQuery

I have a table in BigQuery which looks like this:
The sequence field is a repeated RECORD. I want to select one row per stepName but if there are multiple rows per step name, I want to choose the one where sequence.step.elapsedSeconds and sequence.step.elapsedMinutes are not null, otherwise select the rows where these columns are null.
As shown in the image above, I want to select row no. 2, 4 and 5. I have calculated ROW_NUMBER like this: ROW_NUMBER() OVER(PARTITION BY step.stepName) AS RowNum.
HereĀ“s my query so far in trying to filter out the unwanted rows:
WITH DistinctRows AS
(
select timestamp,
ARRAY (
SELECT
STRUCT(
STRUCT(
step.elapsedSeconds,
step.elapsedMinutes,
) as step
)
FROM
UNNEST(source_table.sequence) AS sequence
) AS sequence,
ROW_NUMBER() OVER(PARTITION BY step.stepName) AS RowNum
from source_table,
unnest(sequence) as previousCalls
order by timestamp asc
)
SELECT *
FROM DistinctRows,
unnest(sequence) as sequence
where (rowNum = 1 and (step.elapsedSeconds is null and step.elapsedMinutes is null)
or (RowNum > 1 and step.elapsedSeconds is not null and step.elapsedSeconds is not null)
order by timestamp asc
I need help in figuring out how to filter out the rows like no. 1 and 3 and would appreciate some help.
Thanks in advance.
Hmmm . . . Assuming that stepname is not part of the repeated column:
SELECT dr.* EXCEPT (sequence),
(SELECT seq
FROM unnest(dr.sequence) seq
ORDER BY seq.step.elapsedSeconds DESC NULLS LAST,
sequence.step.elapsedMinutes DESC NULLS LAST
) as sequence
FROM DistinctRows dr
ORDER BY timestamp asc;
If stepname is part of sequence, then the subquery would reaggregate:
SELECT dr.* EXCEPT (sequence),
(SELECT ARRAY_AGG(sequence ORDER BY stepName)
FROM (SELECT seq,
ROW_NUMBER() OVER (PARTITION BY seq.stepName
ORDER BY seq.step.elapsedSeconds DESC NULLS LAST, sequence.step.elapsedMinutes DESC NULLS
) as seqnum
FROM unnest(dr.sequence) seq
) s
WHERE seqnum = 1
) as sequence
FROM DistinctRows dr
ORDER BY timestamp asc

rownum is not returning anything even if without rownum a record is shown

I have a select statement in DB2 that returns a record when executed however if I add a restriction like rownum >=1 and rownum <=2 no record is being returned.
Select statement:
When I try with:
SELECT person.ID, person.SEX, person.BYEAR, person.BMONTH,
person.BDAY
FROM MIGRATION.LEGALPERSON person
JOIN MIGRATION.LEGALPARTNER part ON person.ID = part.ID
WHERE person.STATUS = 'ACTIVE'
one record is returned.
And with the
SELECT person.ID, person.SEX, person.BYEAR, person.BMONTH,
person.BDAY
FROM MIGRATION.LEGALPERSON person
JOIN MIGRATION.LEGALPARTNER part ON person.ID = part.ID
WHERE person.STATUS = 'ACTIVE' and person.ROWNUM >= 1 and person.ROWNUM <= 2
no record is returned.
What could be the root cause?
You can't use rownum that way (see documentation, https://docs.oracle.com/cd/B19306_01/server.102/b14200/pseudocolumns009.htm):
Conditions testing for ROWNUM values greater than a positive integer are always false
If you want to do something like that, consider using row_number analytic function, e.g.
with temp as
(select some_column,
row_number() over (order by date_value) rn
from your_table
)
select *
from temp
where rn between 4 and 13
As of ROWNUM itself:
with temp as
(select some_column,
rownum rn
from your_table
order by date_value
)
select *
from temp
where rn between 4 and 13

Sql Server Alias name in Row_Number function

select tmp.id, tmp.portfolio,
ROW_NUMBER() OVER(order by tmp.id DESC) AS RowNum
from
(select r.portfolio, r.id
from research r
where r.created_by = 'Adam Cohen'
) as tmp
WHERE RowNum BETWEEN 5 AND 10;
I am not able refer the RowNum in the where condition, as it shows that Invalid column name 'RowNum'. Kindly help me to use the right syntax to get the result.
Edit - Changed Requirement
SELECT * FROM
(
select id, portfolio,
CASE WHEN l.posted_on IS NULL
THEN CONVERT(VARCHAR(40),l.created_on,120)
ELSE CONVERT(VARCHAR(40),l.posted_on,120)
END AS sort_by,
ROW_NUMBER() OVER(order by sort_by DESC) AS RowNum
from research
where created_by = 'Adam Cohen'
) x
WHERE x.RowNum BETWEEN 5 AND 10
I tried to include the Row_Number function like above but I got the sort_by as invalid column.
You'll need to wrap your projection in a derived table, although you can drop the inner tmp table:
SELECT * FROM
(
select id, portfolio,
ROW_NUMBER() OVER(order by id DESC) AS RowNum
from
research
where created_by = 'Adam Cohen'
) x
WHERE x.RowNum BETWEEN 5 AND 10
Edit
Note that if you don't actually need the pseudo row number in the final select, that since Sql 2012, in your 'page of data' scenario, that you will be able to use OFFSET FETCH apply the without the need for ROW_NUMBER() or derived tables at all:
select id, portfolio
from research
where created_by = 'Adam Cohen'
order by id desc
offset 5 rows fetch next 6 rows only;
Edit #2, Re new requirements
CASE WHEN l.posted_on IS NULL
THEN CONVERT(VARCHAR(40),l.created_on,120)
ELSE CONVERT(VARCHAR(40),l.posted_on,120)
END AS sort_by
Can be more concisely expressed as
CONVERT(VARCHAR(40), COALESCE(posted_on, created_on)) AS AS sort_by
However, if you still need original row number, you also use this projection in the ORDER BY of the windowing function (OVER), in order to DRY this up you will need the nested derived table. You can still use the SQL 2012 OFFSET / FETCH NEXT to paginate, however:
SELECT *,
ROW_NUMBER() OVER(order by sort_by DESC) AS RowNum
FROM
(
SELECT id, portfolio, CONVERT(VARCHAR(40), COALESCE(posted_on, created_on)) AS sort_by
from research
where created_by = 'Adam Cohen'
) y
ORDER BY id DESC
OFFSET 5 ROWS FETCH NEXT 6 ROWS ONLY;
You need to nest the ROW_NUMBER in the Derived Table:
select tmp.id, tmp.portfolio, tmp.RowNum
from
(select r.portfolio, r.id,
ROW_NUMBER() OVER(order by r.id DESC) AS RowNum
from research r
where r.created_by = 'Adam Cohen'
) as tmp
WHERE RowNum BETWEEN 5 AND 10;

Select Nth Row From A Table In Oracle

How can I select the Nth row from a table in Oracle?
I tried
SELECT PRICE FROM AAA_PRICING WHERE ROWNUM = 2
but that didn't work. Please help!
Based on the classic answer:
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:127412348064
select *
from ( select a.*, rownum rnum
from ( YOUR_QUERY_GOES_HERE -- including the order by ) a
where rownum <= N_ROWS )
where rnum >= N_ROWS
/
Will not works with '=' (will works <2 or >2, but not equal)
so you can
SELECT Price from (SELECT PRICE, ROWNUM AS RN FROM AAA_PRICING) WHERE RN = 2
To address the reason for this:
The RowNum is a pseudo-column supplied by Oracle. It is generated while the SELECT-clause is being processed. Since the WHERE-clause is handled before the SELECT-clause, the RowNum does not have a proper value yet.
One can argue whether or not it makes sense to have Oracle throw an exception in situation, but because RowNum still is a pseudo-column it's still valid to have it there.
Note: Don't confuse this with RowId, which is an entire different story!
IMPORTANT EDIT:
Note that what I wrote about RowNum is only true for =, >, >=, IN () and maybe others. If you check for, e.g. RowNum < 10, you only get nine records!? I don't know why that is the case!
Select * From
(
Select Row_Number() OVER (Order by empno) rno, e.*
From scott.emp e
)
Where rno in (1, 3, 11)
SELECT PRICE
FROM (
SELECT PRICE,
ROWNUM rnum
FROM AAA_PRICING
ORDER BY PRICE ASC
)
WHERE rnum = 2
If you are on Oracle 12 or above, You can use the result offset and fetch clauses:
SELECT PRICE FROM AAA_PRICING
offset 1 rows fetch next 1 rows only
SELECT * FROM
(SELECT PRICE, ROWNUM AS RN FROM AAA_PRICING )
WHERE RN = 2;
select * from (Select Price, rownum as rn from(Select * from AAA_PRICING a order by a.Price))
where rn=2;
It will give you 2nd lowest price from the Price column. If you want simply 2nd row remove Order By condition.
ROWNUM is a pseudo column which generates unique pseudo values (equals to the number of records present in the SELECT statement o/p) during the execution of SELECT clause. When this pseudo column is specified with the WHERE clause it's value becomes 1 by default. So it behaves according to the comparison operator specified with it.
SELECT * FROM (
SELECT ROWNUM RN, E.*
FROM Emp E
)
WHERE RN = 10;
select *
From (select PRICE, DENSE_RANK() over(ORDER BY PRICE desc) as RNO
From AAA_PRICING
) t where RNO=2;
select a.*, rownum rnum
from ( select * from xyz_menu order by priority desc) a
where rownum < 5 ;
select * from xyz_menu order by priority desc
creating virtual table and also defining row number in virtual table
note: for oracle
Problem solved!
To select 2nd row in Oracle..
select SEN_NO,ITEM_NO from (select * from master_machine where
sen_no ='BGCWKKL23' and rownum <=2 order by
rownum desc,timestamp asc) where rownum <=1
Thank You!

Retrieving the second most highest value from a table

How do I retrieve the second highest value from a table?
select max(val) from table where val < (select max(val) form table)
In MySQL you could for instance use LIMIT 1, 1:
SELECT col FROM tbl ORDER BY col DESC LIMIT 1, 1
See the MySQL reference manual: SELECT Syntax).
The LIMIT clause can be used to constrain the number of rows returned by the SELECT statement. LIMIT takes one or two numeric arguments, which must both be nonnegative integer constants (except when using prepared statements).
With two arguments, the first argument specifies the offset of the first row to return, and the second specifies the maximum number of rows to return. The offset of the initial row is 0 (not 1):
SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15
select top 2 field_name from table_name order by field_name desc limit 1
SELECT E.lastname, E.salary FROM employees E
WHERE 2 = (SELECT COUNT(*) FROM employess E2
WHERE E2.salary > E.salary)
Taken from here
This works in almost all Dbs
Select Top 1 sq.ColumnToSelect
From
(Select Top 2 ColumnToSelect
From MyTable
Order by ColumnToSelect Desc
)sq
Order by sq.ColumnToSelect asc
Cool, this is almost like Code Golf.
Microsoft SQL Server 2005 and higher:
SELECT *
FROM (
SELECT
*,
row_number() OVER (ORDER BY var DESC) AS ranking
FROM table
) AS q
WHERE ranking = 2
Try this
SELECT * FROM
(SELECT empno, deptno, sal,
DENSE_RANK() OVER (PARTITION BY deptno ORDER BY sal DESC NULLS LAST) DENSE_RANK
FROM emp)
WHERE DENSE_RANK = 2;
This works in both Oracle and SQL Server.
Try this
SELECT TOP 1 Column FROM Table WHERE Column < (SELECT MAX(Column) FROM Table)
ORDER BY Column DESC
SELECT TOP 1 Column FROM (SELECT TOP <n> Column FROM Table ORDER BY Column DESC)
ORDER BY ASC
change the n to get the value of any position
Maybe:
SELECT * FROM table ORDER BY value DESC LIMIT 1, 1
one solution would be like this:
SELECT var FROM table ORDER BY var DESC LIMIT 1,1