How to get nth record in a sql server table without changing the order?(sql server) - sql

for example i have data like this(sql server)
id name
4 anu
3 lohi
1 pras
2 chand
i want 2nd record in a table (means 3 lohi)
if i use row_number() function its changes the order and i get (2 chand)
i want 2nd record from table data
can anyonr please give me the query fro above scenario

There is no such thing as the nth row in a table. And for a simple reason: SQL tables represent unordered sets (technically multi-sets because they allow duplicates).
You can do what you want use offset/fetch:
select t.*
from t
order by id desc
offset 1 fetch first 1 row only;
This assumes that the descending ordering on id is what you want, based on your example data.
You can also do this using row_number():
select t.*
from (select t.*,
row_number() over (order by id desc) as seqnum
from t
) t
where seqnum = 2;
I should note that that SQL Server allows you to assign row_number() without having an effective sort using something like this:
select t.*
from (select t.*,
row_number() over (order by (select NULL)) as seqnum
from t
) t
where seqnum = 2;
However, this returns an arbitrary row. There is no guarantee it returns the same row each time it runs, nor that the row is "second" in any meaningful use of the term.

Related

SQL query looping for each value in a list

New to SQL here - I am trying to get 1 row from a table matching to a particular criteria
Typically this would look like
SELECT TOP 1 *
FROM myTable
WHERE id = 'abc'
The output may look like
value id
--------------
1 abc
The table has many entries for an 'id', and I am trying to get one entry per 'id'. Now I have list of 'id's. How would I execute something like
SELECT TOP 1 *
FROM myTable
FOR EACH id
WHERE id IN ('abc', 'edf', 'fgh')
Expecting result like
value id
--------------
1 abc
10 edf
12 fgh
I do not know if it is some sort union or concat operation, but would like to learn. I am working on Azure SQL Server
The table has many entries for an 'id', and I am trying to get one entry per 'id'. Now I have list of 'id's.
A typical method is row_number():
select t.*
from (select t.*,
row_number() over (partition by id order by id) as seqnum
from mytable t
) t
where seqnum = 1;
Note: you can filter on particular ids, if you want. It is unclear if that is really required for your question.
If you happen to be using SQL Server (as select top suggests), you can use the more concise, but somewhat less performant:
select top (1) with ties t.*
from mytable t
order by row_number() over (order by id order by (select null));

How to get 10 of the results in every group of a table using Hive sql?

I have a table
I want to group the data by class, then every class pick out two of the data,whatever sorting or not.
then get results like this.
How to write the sql?
Use row_number():
select t.*
from (select t.*, row_number() over (partition by class order by class) as seqnum
from t
) t
where seqnum <= 2;
If you want two particular rows -- such as the two highest scoring or lowest scoring -- then adjust the order by clause.

Ranking over several columns

In the process of query optimization I got to following SQL query:
select s.*
from
(
select id, DATA, update_dt, inspection_dt, check_dt
RANK OVER()
(PARTITION by ID
ORDER BY update_dt DESC, DATA) rank
FROM TABLE
where update_dt < inspection_dt or update_dt < check_dt
) r
where r.rank = 1
Query returns the DATA that corresponds to the latest check_dt.
However, what I want to get is:
1. DATA corresponding to latest check_dt
2. DATA corresponding to latest inspection_dt.
One of the trivial solutions - just write two separate queries with a where single condition - one for inspection_dt, and one for check_dt. However, that way it loses initial intent - to shorten the running time.
By observing the source data I noticed the way to implement it - check date is always later than inspection date; knowing that I could just extract the record with the rank = 1 and it will give me DATA corresponding to latest CHECK_DT, and record with the largest rank would correspond to INSPECTION.
However, data I'm afraid data will not be always consistent, so I was looking for more abstract solution.
How about this?
select s.*
from (select id, DATA, update_dt, inspection_dt, check_dt,
RANK() OVER (PARTITION by ID
ORDER BY update_dt DESC, DATA
) as rank_upd,
RANK() OVER (PARTITION by ID
ORDER BY inspection_dt DESC, DATA
) as rank_insp,
FROM TABLE
) r
where r.rank_upd = 1 or r.rank_insp = 1;

TOP 1 with grouping

I have the followin table structure
person_id organization_id
1 1
1 2
1 3
2 4
2 2
I want the result set as
person_id organization_id
1 1
2 4
means TOP1 of the person_id
You are using SQL Server, so you can use row_number(). However, you really cannot define top without ordering -- the results are not guaranteed.
So, the following will do a top without an order by:
select person_id, min(organization_id)
from t
group by person_id;
However, I assume that you intend for the order of the rows to be the intended order. Alas, SQL tables are unordered so the ordering is not valid. You really need an id or creationdate or something to specify the order.
All that said, you can try the following:
select person_id, organization_id
from (select t.*,
row_number() over (partition by person_id order by (select NULL)) as seqnum
from t
) t
where seqnum = 1;
It is definitely not guaranteed to work. In my experience, the order by (select NULL)) returns rows in the same order as the select -- although there is no documentation to this effect (that I have found). Note that in a parallel system on a decent sized table, SQL Server return order has little to do with the order of the rows on the pages or the insert order.

Oracle Select query help please

SELECT id
FROM (
SELECT id
FROM table
WHERE
PROCS_DT is null
ORDER BY prty desc, cret_dt ) where rownum >0 and rownum <=100
The above query is giving me back 100 records as expected
SELECT id
FROM (
SELECT id
FROM table
WHERE
PROCS_DT is null
ORDER BY prty desc, cret_dt ) where rownum >101 and rownum <=200
why is the above query returning me zero records?
Can some one help me how i can keep on. I am dumb in oracle...
Try this:
SELECT id
FROM
(SELECT id,
rownum AS rn
FROM
(SELECT id
FROM TABLE
WHERE PROCS_DT IS NULL
ORDER BY prty DESC, cret_dt) )
WHERE rn >101
AND rn <=200
If you are comfortable using the ANALYTIC functions, try this:
SELECT id
FROM
(
SELECT id,
ROW_NUMBER() OVER(ORDER BY prty DESC, cret_dt ) rn
FROM table
WHERE procs_dt IS NULL
)
WHERE rn >101 and rn <=200
ROWNUM values are assigned to rows as they are returned from a query (or subquery). If a row is not returned, it is not assigned a ROWNUM value at all; so the ROWNUM values returned always begin at 1 and increment by 1 for each row.
(Note that these values are assigned prior to any sorting indicated by the ORDER BY clause. This is why in your case you need to check rownum outside the subquery.)
The odd bit of logic you have to understand is that when you have a predicate on ROWNUM, you are filtering on a value that will only exist if the row passes the filter. Conceptually, Oracle applies any other filters in the query first, then tentatively assigns ROWNUM 1 to the first matching row and checks it against the filter on ROWNUM. If it passes this check, it will be returned with that ROWNUM value, and the next row will be tentatively assigned ROWNUM 2. But if it does not pass the check, the row is discarded, and the same ROWNUM value is tentatively assigned to the next row.
Therefore, if the filter on ROWNUM does not accept a value of 1, no rows will ever pass the filter.
The use of the analytic function ROW_NUMBER() shown in the other answers is one way around this. This function explicitly assigns row numbers (distinct from ROWNUM) based on a given ordering. However, this can change performance significantly, as the optimizer does not necessarily realize that it can avoid assigning numbers to ever possible row in order to complete the query.
The traditional ROWNUM-based way of doing what you want is:
SELECT id
FROM (
SELECT rownum rn, id
FROM (
SELECT id
FROM table
WHERE
PROCS_DT is null
ORDER BY prty desc, cret_dt
) where rownum <=200
) where rn > 101
The innermost query conceptually finds all matching rows and sorts them. The next layer assigns ROWNUMs to these and returns only the first 200 matches. (And actually, the Oracle optimizer understands the significance of a sort followed by a ROWNUM filter, and will usually do the sort in such a way as to identify the top 200 rows without caring about the specific ordering of the other rows.)
The middle layer also takes the ROWNUMs that it assigns and returns them as part of its result set with the alias "rn". This allows the outermost layer to filter on that value to establish the lower limit.
I would experiment with this variant and the analytic function to see which performs better in your case.