Selecting Second row if available if not first in SQL - sql

I have a table that looks like below:
i want to Select Operator entry that corresponds to RowNumber 2 of InstanceNumber 1 and rownumber 1 of other instances. This is one example where only instancenumber 1 has two rownumber's but I want to able to pick last rownumber of each intances. Any help is appreciated.

One method uses window functions:
select t.*
from (select t.*, max(rownumber) over (partition by instancenumber) as maxrn
from t
) t
where rownumber = maxrn;
That said, if you have the right indexes, the following might be a tad faster:
select t.*
from t
where t.rownumber = (select max(t2.rownumber) from t t2 where t2.instancenumber = t.instancenumber);

Related

How to group and pick only certain values based on a field using select query SQL

I have a table as follow
ID
ORDERNO
1
123
1
123
2
456
2
456
During every select query done via application using JDBC, only the grouped records based on ORDERNO should be picked.
That means, for example, during first select query only details related to ID = 1, but we cannot specify the ID number in where clause because we do not know how many number of IDs will be there in future. So the query should yield only one set of records; application will delete those records after picking, hence next select query will result in picking other set of records. How to achieve it?
You can use TOP WITH TIES for this
SELECT TOP (1) WITH TIES
t.ID,
t.ORDERNO
FROM YourTable t
ORDER BY
t.ID;
If you want to select and delete at the same time you could delete using an OUTPUT clause
WITH cte AS (
SELECT TOP (1) WITH TIES
t.ID,
t.ORDERNO
FROM YourTable t
ORDER BY
t.ID
)
DELETE cte
OUTPUT deleted.*;
As one option you could select on the MIN(ID) like:
SELECT *
FROM yourtable
WHERE ID = (SELECT MIN(ID) FROM yourtable);
You could also use window functions to do this:
SELECT ID, ORDERNO
FROM
(
SELECT ID, ORDERNO
DENSE_RANK() OVER (ORDER BY ID ASC) AS dr
FROM yourtable
)dt
WHERE dr = 1;
order your rows and select top n number of rows that you want :
select top (1) with ties ID, ORDERNO
from tablename
order by ID asc

Avoid duplicate records from a particular column of a table

I have a table as shown in the image.In Number column, the values are appeared more than once (for example 63 appeared twice). I would like to keep only one value. Please see my code:
delete from t1 where
(SELECT *,row_number() OVER (
PARTITION BY
Number
ORDER BY
Date) as rn from t1 where rn > 1)
It shows error. Can anyone please assist.
enter image description here
The column created by row_number() was not accessed by your main query, in order to enable that, you can create a quick sub query and use the desired filter
SELECT *
FROM
(
SELECT *,
row_number() OVER (PARTITION BY Number ORDER BY Date) as rn
FROM t1 ) T
where rn = 1;
The partition by determines how row numbers repeat. The row numbers are assigned per group of partition by keys. So, you can get duplicates.
If you want a unique row number over all rows, just leave out the partition by:
select t1.*
from (select t1.*,
row_number() over (order by date) as rn
from t1
) t1
where rn > 1
if you want to keep only one value, rn = 1 instead of "> 1"

SQL query to get maximum value for each day

So I have a table that looks something like this:
Now, I want the max totalcst for both days, something like this:
I tried using different variations of max and the Row_number funtion but still can't seem to get the result I want. My query:
select date,pid,max(quan*cst), totalcst
from dbo.test1
group by date, pid
But this returns all the records. So if somebody can point me towards the right direction, that would be very helpful.
Thanks in advance!
ROW_NUMBER should work just fine:
WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY [date] ORDER BY totalcst)
FROM dbo.YourTable
)
SELECT [date],
pid,
totalcst
FROM CTE
WHERE RN = 1
;
Here is one simple way:
select t.*
from test1 t
where t.totalcst = (select max(t2.totalcst) from test1 t2 where t2.date = t.date);
This often has the best performance if you have an index on (date, totalcst). Of course, row_number()/rank() is also a very acceptable solution:
select t.*
from (select t.*, row_number() over (partition by date order by totalcst desc) as seqnum
from test1
) t
where seqnum = 1;

Select Top 100 Groups

I have thousands of groups in a table, something like :
1..
1..
2..
2..
2..
2..
3..
3..
.
.
.
10000..
10000..
How can i make a select that give me the Top 3 groups each time.
I Want something like select Top 3 from rows , but it have to return the first three groups not the first three rows.
You can try this :
;with cte as (
select distinct groupId from mytable order by groupid
)
select * from mytable where TheGroupId in (select top 3 groupdid from cte)
You can use DENSE_RANK to assign a number to each group. All members of the same group will have the same number. Then in an outer query, select top 3 groups:
SELECT *
FROM (SELECT *, DENSE_RANK() OVER (ORDER BY id) AS rnk
FROM mytable ) t
WHERE t.rnk <= 3
The above query assumes that id is the column used to group records together.
SQL Fiddle Demo
Use Ranking function Row_Number() :
SELECT *
FROM (SELECT *,
Row_number()
OVER(
partition BY GroupId
ORDER BY GroupId) AS [rn]
FROM YourTable) t
WHERE rn <= 3
Check this MSDN doc for details of all ranking functions.
There is a sql TOP statement that does this
SELECT TOP number|percent column_name(s) FROM table_name;
a description of what it does and how it is used in alternative sql statements for example for mysql and ms access can be found here: http://www.w3schools.com/sql/sql_top.asp
My bad i misread your question, this will return the top rows not groups, could you explain what you are trying to do in more detail?
SELECT *
FROM
(SELECT *
,ROW_NUMBER() OVER (PARTITION BY [Group] ORDER BY [Group] ASC)rn
FROM TableName
)A
WHERE rn <= 3

SQL Server select first instance of ranked data with a twist

I have a Table1 that look like this:
Wallet No Status Rank
01774076563 Scanned 1
01765653275 Registered 3
01774076563 Accepted 2
01768836816 Rejected 4
01967866981 Accepted 2
01967866981 Rejected 4
I want it to look like this (Table2):
Wallet No Status Rank
01774076563 Scanned 1
01765653275 Registered 3
01768836816 Rejected 4
01967866981 Accepted 2
I have used following code but it shows Table1 instead of Table2:
SELECT MIN([Rank]) AS [Rank], STATUS_, walletno into table2
FROM table1
GROUP BY STATUS_, walletno
What I want is only the highest ranking wallet no and status, nothing else. But the Table2 gives me exact copy of Table1. What am I doing wrong here?
You are looking for the complete row, rather than just the minimum value. For this, the window functions are handy.
Because your logic uses min(), here is a method using that function:
SELECT [Rank], STATUS_, walletno into table2
FROM (select t.*,
MIN([rank]) over (partition by walletno) as minrank
from table1 t
) t
where [rank] = minrank;
The subquery calculates the minimum rank for each wallet. The outer filter than keeps only that row.
I would normally write this with row_number() as:
SELECT [Rank], STATUS_, walletno into table2
FROM (select t.*,
row_number() over (partition by walletno order by [rank]) as seqnum
from table1 t
) t
where seqnum = 1;
But the two should be pretty similar in terms of performance. The major difference is when two rows have the same minimum rank. The first version will return both rows. The second will arbitrarily choose one of them.
You can try this:
;WITH CTE as
(
SELECT
WalletNo,
Status,
ROW_NUMBER() OVER(PARTITION BY Status ORDER BY Rank) AS Row,
Rank
FROM
Item
)
SELECT WalletNo, Status, Row, Rank From CTE Where Row = 1
Fiddle here: http://sqlfiddle.com/#!3/14fa5/6