DENSE_RANK() Query - sql

I have something similar to the below dataset...
ID RowNumber
101 1
101 2
101 3
101 4
101 5
101 1
101 2
What I would like to get is an additional column as below...
ID RowNumber New
101 1 1
101 2 1
101 3 1
101 4 1
101 5 1
101 1 2
101 2 2
I have toyed with dense_rank(), but no such luck.

Gordon already mentioned, you required a column to specify the order of data. If i consider ID as order by column, this following logic may help you to get your desired result-
WITH your_table(ID,RowNumber)
AS
(
SELECT 101,1 UNION ALL
SELECT 101,2 UNION ALL
SELECT 101,3 UNION ALL
SELECT 101,4 UNION ALL
SELECT 101,5 UNION ALL
SELECT 101,1 UNION ALL
SELECT 101,2
)
SELECT A.ID,A.RowNumber,
SUM(RN) OVER
(
ORDER BY ID
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) +1 New
FROM
(
SELECT *,
CASE
WHEN LAG(RowNumber) OVER(ORDER BY ID) > RowNumber THEN 1
ELSE 0
END RN
FROM your_table
)A
Above will always change the ROW NUMBER if the value in RowNumber decreased than previous one. Alternatively, the same output alsoo can be achieved if you wants to change row number whenever value 1 found. This is bit static option-
SELECT A.ID,A.RowNumber,
SUM(RN) OVER
(
ORDER BY ID
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) New
FROM(
SELECT *,
CASE
WHEN RowNumber = 1 THEN 1
ELSE 0
END RN
FROM your_table
)A
Output is-
ID RowNumber New
101 1 1
101 2 1
101 3 1
101 4 1
101 5 1
101 1 2
101 2 2

SQL tables represent unordered sets. There is no ordering unless a column specifies the ordering.
Assuming you have such a column, you can do what you want simply by counting the number of "1" up to each point:
select t.*,
sum(case when rownumber = 1 then 1 else 0 end) over (partition by id order by <ordering column>) as new
from t;

As Gordon alluded to, there is no default order in your example so it's difficult to imagine how to get a deterministic result (e.g. where the same values supplied to the same query always resulting in the exact same answer.)
This sample data includes a sequential PK column which is used to define the order of this set.
DECLARE #tbl TABLE (PK INT IDENTITY, ID INT, RowNumber INT)
INSERT #tbl(ID, RowNumber) VALUES (101,1),(101,2),(101,3),(101,4),(101,5),(101,1),(101,2);
SELECT t.* FROM #tbl AS t;
Returns:
PK ID RowNumber
----- ------ -----------
1 101 1
2 101 2
3 101 3
4 101 4
5 101 5
6 101 1
7 101 2
This query uses DENSE_RANK to get you what you want:
DECLARE #tbl TABLE (PK INT IDENTITY, ID INT, RowNumber INT)
INSERT #tbl(ID, RowNumber) VALUES (101,1),(101,2),(101,3),(101,4),(101,5),(101,1),(101,2);
SELECT t.ID, t.RowNumber, New = DENSE_RANK() OVER (ORDER BY t.PK - RowNumber)
FROM #tbl AS t;
Returns:
ID RowNumber New
----- ----------- ------
101 1 1
101 2 1
101 3 1
101 4 1
101 5 1
101 1 2
101 2 2
Note that ORDER BY New does not affect the plan.

Please try the below
Load the data into Temp table
Select id,RowNumber,Row_number()over(partition by RowNumber Order by id)New from #temp
Order by Row_number()over(partition by RowNumber Order by id),RowNumber

Related

Return 1 row from all groups

https://dbfiddle.uk/?rdbms=sqlserver_2016&fiddle=9e6f83edf836f4496afb509eb9411d4a
Edited to include sql code:
CREATE TABLE TMP_PRODUCTS (STORE INT, UPC INT, PROMOCODE CHAR(3), FORSALE CHAR(1))
INSERT INTO TMP_PRODUCTS VALUES
(100,1,'123','Y'),
(100,2,'123','Y'),
(100,3,'123','N'),
(100,4,'124','Y'),
(100,5,'124','N'),
(100,6,'124','N'),
(100,7,'125','N'),
(100,8,'125','N'),
(100,9,'125','N');
SELECT
STORE,
UPC,
PROMOCODE,
DENSE_RANK() OVER (PARTITION BY STORE ORDER BY PROMOCODE) AS 'GroupCode'
FROM
TMP_PRODUCTS
WHERE
FORSALE = 'Y'
I need to return all rows where FORSALE='Y' across all groups of PROMOCODE, and also at least 1 row from all groups where FORSALE='N'. In this example all products from group 125 are FORSALE='N', but I need at least 1 row to return. Here is the output I am currently getting:
STORE UPC PROMOCODE GroupCode FORSALE
100 1 123 1 Y
100 2 123 1 Y
100 4 124 2 Y
But here is the ideal output I would like to get:
STORE UPC PROMOCODE GroupCode FORSALE
100 1 123 1 Y
100 2 123 1 Y
100 4 124 2 Y
100 7 125 3 N
It would also be completely acceptable to return 1 row from PROMOCODE 123 and 124 even though they already have some items that are FORSALE='Y'. So this would also be acceptable outcome:
STORE UPC PROMOCODE GroupCode FORSALE
100 1 123 1 Y
100 2 123 1 Y
100 3 123 1 N
100 4 124 2 Y
100 5 124 2 N
100 7 125 3 N
You can do that with an additional row number window function to always include 1 row from each group regardless of Y/N
select STORE, UPC, PROMOCODE, Dense_Rank() over (partition by STORE order by PROMOCODE) GROUPCODE, FORSALE
from (
select * , Row_Number() over(partition by STORE, PROMOCODE order by UPC) rn
from TMP_PRODUCTS
)x
where FORSALE = 'Y' or rn=1
If I understand correctly, the logic you want is:
SELECT STORE, UPC, PROMOCODE,
DENSE_RANK() OVER (PARTITION BY STORE ORDER BY PROMOCODE) AS GroupCode
FROM (SELECT P.*,
ROW_NUMBER() OVER (PARTITION BY STORE, PROMOCODE, FORSALE ORDER BY (SELECT NULL)) as seqnum
FROM TMP_PRODUCTS P
) P
WHERE FORSALE = 'Y' OR seqnum = 1;

DB2 Toad SQL - Group by Certain Columns using Max Command

I am having some trouble with the below query. I do understand I need to group by ID and Category, but I only want to group by ID while keeping the rest of the columns based on Rank being max. Is there a way to only group by certain columns?
select ID, Category, max(rank)
from schema.table1
group by ID
Input:
ID Category Rank
111 3 4
111 1 5
123 5 3
124 7 2
Current Output
ID Category Rank
111 3 4
111 9 1
123 5 3
124 7 2
Desired Output
ID Category Rank
111 1 5
123 5 3
124 7 2
You can use:
select *
from table1
where (id, rank) in (select id, max(rank) from table1 group by id)
Result:
ID CATEGORY RANK
---- --------- ----
111 1 5
123 5 3
124 7 2
Or you can use the ROW_NUMBER() window function. For example:
select *
from (
select *,
row_number() over(partition by id order by rank desc) as rn
from table1
) x
where rn = 1
See running example at db<>fiddle.
You can try using - row_number()
select * from
(
select ID, Category,rank, row_number() over(partition by id order by rank desc) as rn
from schema.table1
)A where rn=1

Need to select 1 row from each group in sql

am trying to do this query. This is what I have.
My table is: Table
QId InternalId type. priority userid
100 100 1 0 X101
100 100 1 1 X102
100 100 2 0 X103
100 100 2 0 X104
100 100 2 0 X105
100 100 3 0 X106
100 100 3 0 X107
101 101 2 1 X114
101 101 2 0 X115
101 101 3 0 X116
101 101 3 0 X117
For QId and InternalId we have type 1,2,3. I need 1 row for each group based type. Here condition is if priority is 1 then we need take that record. if priority is not set need to take first record.
I need result like below table
QId InternalId type. priority userid
100 100 1 1 X102
100 100 2 0 X103
100 100 3 0 x106
101 101 2 1 X114
101 101 3 0 X116
Can you please help me out in this
Just use row_number():
select t.*
from (select t.*,
row_number() over (partition by QId, InternalId, type order by (select null)) as seqnum
from t
) t
where seqnum = 1;
You can try using row_number()
select * from
(
select *, row_number() over(partition by qid, internalid, type order by priority desc) as rn
from tablename
)A where rn=1
use row_number() window function
select t.* from (select *,row_number()over(partition by QId,InternalId,type order by case when priority=1 then 1 else 2 end) rn
) where t.rn=1
Another approach can be WITH TIES like following.
select top 1 with ties *
from #table
order by row_number() over (partition by QId, InternalId, type order by (select 1))
Online Demo

Update Last Row as First row Value

I have table in below format
SeqID Control_ID Data_Value RowNum
1 SEARCH SEARCH 3
1 BROKERREF BZ815 4
1 SYSTEM 0 5
2 pdp pdp 1
2 test 123 2
2 system 235 3
I want to update the table to be in below format
SeqID Control_ID Data_Value RowNum
1 BROKERREF BZ815 4
1 SYSTEM 0 5
1 SEARCH SEARCH 3
2 test 123 2
2 system 235 3
2 pdp pdp 1
I need to select the top row as a last row for each group of sequence ID.
Note : Control_Id and DataValue Column name will be same for the row which need to be selected as a last row for each unique sequenceID
Thanks in advance.
Use ROW_NUMBER() to locate the first row per SeqID. Then, in an outer query, use CASE expression in the ORDER BY clause to place this row in the last
position within its partition:
SELECT SeqID, Control_ID, Data_Value, RowNum
FROM (
SELECT SeqID, Control_ID, Data_Value, RowNum,
ROW_NUMBER() OVER (PARTITION BY SeqID ORDER BY RowNum) AS rn
FROM mytable ) t
ORDER BY SeqID,
CASE WHEN t.rn = 1 THEN 1 ELSE 0 END,
RowNum
SQL Fiddle Demo

SQL Query to find the most recent group of records

I have a history of records (multiple records per update all with the exact same datetime) that share an IdString.
I want a query to determine which of these records are part of the most recent update group.
This query will show me one of the records having the most recent update date, but for each partition, I need all the records with that max date.
;with cte as(
select ROW_NUMBER() over (partition by IdString order by UpdateDate desc) as [rn], *
from MyTable
)
select CASE WHEN (cte.rn = 1) THEN 0 ELSE 1 END [IsOld], *
from MyTable m
inner join cte on cte.RecordId= m.RecordId
Would someone please help me figure out an appropriate query?
EDIT: Sample
(IsOld is the desired calculated value)
IsOld RecordId IdString UpdateDate
1 1 ABC 2011-06-16
1 2 ABC 2012-05-30
1 3 ABC 2008-12-31
0 4 ABC 2012-06-08
1 5 ABC 2011-01-16
0 6 ABC 2012-06-08
1 7 ABC 2012-06-07
1 8 XYZ 2001-01-16
1 9 XYZ 2013-01-30
0 10 XYZ 2001-01-31
1 11 XYZ 2013-06-01
1 12 XYZ 2001-05-04
0 13 XYZ 2013-01-30
SELECT CASE WHEN updateDate = maxDate THEN 0 ELSE 1 END isOldRecord, RecordID, IDString, UpdateDate
FROM
(
select m.RecordID, m.IDString, m.updateDate, MAX(UpdateDate) OVER (PARTITION BY IDString) maxDate
from MyTable m
) A
Try this -
;WITH cte AS(
SELECT RANK() OVER(PARTITION BY IdString ORDER BY UpdateDate DESC) AS [row_num], *
FROM MyTable
)
SELECT CASE WHEN m.[row_num] = 1 THEN 0 ELSE 1 END isOld, *
from cte m