DENSE_RANK() OVER ( PARTITION by - snowflake-cloud-data-platform

I've: DENSE_RANK() OVER ( PARTITION BY state ORDER BY population desc) as ranking
I'd like to skip the first 10 results of my ranking and limit it to 50 results per state. Is this possible?

so:
with data(state, pop) as (
select * from values
(1,10),
(1,10),
(1,11),
(1,12),
(2,10),
(2,11),
(2,12),
(2,12)
)
select d.*
,DENSE_RANK() OVER ( PARTITION BY state ORDER BY pop desc) as ranking
from data as d
gives:
STATE
POP
RANKING
2
12
1
2
12
1
2
11
2
2
10
3
1
12
1
1
11
2
1
10
3
1
10
3
so we can use QAULIFY to only keep those >= 3 to avoid the first "2"
select d.*
,DENSE_RANK() OVER ( PARTITION BY state ORDER BY pop desc) as ranking
from data as d
qualify ranking >= 3
STATE
POP
RANKING
2
10
3
1
10
3
1
10
3
but this shows, as we had 4 per set, we have removed 2,3 respectively from the two sets.
This can also be down with the DENSE_RANK in the QUALIFY like:
select d.*
from data as d
qualify DENSE_RANK() OVER ( PARTITION BY state ORDER BY pop desc) >= 3
STATE
POP
2
10
1
10
1
10
thus skipping the 10's and take things up to the 50's can be done with:
qualify DENSE_RANK() OVER ( PARTITION BY state ORDER BY pop desc) between 10 and 50
but if you really want the absolute first 10 skipped and 50 or less rows, you should use a non-duplicating rank like ROW_NUMBER, thus to skip 10 and take make 50 per state:
qualify ROW_NUMBER() over (PARTITION by state order by pop desc) between 10 and 60

Related

How can I use Row Num partition by different default value

I have something like
ID Mobile isOptOut
1 123 1
2 123 0
3 123 0
4 123 1
5 234 1
6 234 0
to have something like partition by mobile and isOptOut
if the isOptOut is equal to 1 start from 0
otherwise start from 6
ID Mobile isOptOut RowNum
1 123 1 0
4 123 1 1
2 123 0 6
3 123 0 7
5 234 1 0
6 234 0 6
select *,
case when isOptOut = 0 then ROW_Number() OVER(
PARTITION BY Mobile ,isOptOut
order by Mobile ,isOptOut
) as [Row Number]
from r
where isOptOut = 1
Thanks so much
You've on the right path with the window ROW_NUMBER function. However,
As you want to number all the rows, you'll need it for all rows (not just isOptOut = 0)
In the window function, I've ordered it by ID so it will always return the same values (if you order by the same fields as the partition, then they could come out in any order)
Once you have the row_numbers, add the modifier e.g., if isOptOut = 0, add 5 to the row number; or if it's 1, subtract 1
; WITH src AS
(select *,
ROW_Number() OVER(
PARTITION BY Mobile, isOptOut
ORDER BY ID -- Note I changed this to 'ID' for ordering
) as [rn]
FROM r
)
SELECT ID, Mobile, isOptOut,
CASE isOptOut
WHEN 0 THEN rn + 5
WHEN 1 THEN rn - 1
ELSE NULL
END AS RowNum
FROM src
SELECT ID,Mobile,isOptOut, IIF(isOptOut=1,ROWNUMBER-1,ROWNUMBER+5),ROWNUMBER FROM (
SELECT *, (ROW_Number() OVER(
PARTITION BY Mobile,isOptOut ORDER BY ID, Mobile,isOptOut )) ROWNUMBER
FROM #table) as T ORDER BY ID
I think subquery and IIF suit you to reach your target. I created a window function and in the main query the condition.

How to write this query without cursor in SQL Server 2008 R2?

I have this table ScoreDetails, 2 columns (there are more, but only 2 needed or this query). One is ScoreDate, Score.
The structure is like
2012:03:27: 5:06:37:134 27
2012:03:27: 5:06:37:276 37
2012:03:28: 4:12:97:019 19
2012:03:29: 7:06:37:134 7
2012:03:29: 8:06:37:134 0
2012:04:03: 12:06:37:739 16
2012:04:04: 23:21:15:834 33
2012:04:04: 15:08:24:697 12
2012:04:06: 5:06:37:134 0
2012:04:09: 5:06:37:134 2
2012:04:13: 5:06:37:134 92
What I want is to write a select query, without using temp table or cursor. Such that, I have a column that starts from 1 and keeps on increasing as 2,3 and so on, upto when the score is non-zero. But as soon as a zero is encountered in score column, it resets to 1 and then start again. Like this...
2012:03:27: 5:06:37:134 27 1
2012:03:27: 5:06:37:276 37 2
2012:03:28: 4:12:97:019 19 3
2012:03:29: 7:06:37:134 7 4
2012:03:29: 8:06:37:134 0 0
2012:04:03: 12:06:37:739 16 1
2012:04:04: 23:21:15:834 33 2
2012:04:04: 15:08:24:697 12 3
2012:04:06: 5:06:37:134 0 0
2012:04:09: 5:06:37:134 2 1
2012:04:13: 5:06:37:134 92 2
I am using SQL Server 2008 R2.
You can use common table expressions for that. I defined 2 anchor queries: one for records with 0 score and the other for the first record. Then you build up the result based on previous results until you find 0 score.
with cte
as
(
select ScoreDate, Score, ScoreRank, 0 as Value
from (select ScoreDate, Score, dense_rank() over (order by ScoreDate) ScoreRank
from ScoreDetails) X
where Score = 0
union all
select ScoreDate, Score, ScoreRank, 1 as Value
from (select ScoreDate, Score, dense_rank() over (order by ScoreDate) ScoreRank
from ScoreDetails) X
where Score <> 0 and ScoreRank = 1
union all
select X.ScoreDate, X.Score, X.ScoreRank, cte.Value + 1 as Value
from (select ScoreDate, Score, dense_rank() over (order by ScoreDate) ScoreRank
from ScoreDetails) X
inner join cte
on X.ScoreRank = cte.ScoreRank + 1
and X.Score <> 0
)
select ScoreDate, Score, Value, ScoreRank
from cte
order by ScoreDate
SQL Fiddle Demo
I won't spoil the fun of finding the solution yourself, but I will give you some hints on how to split the problem into smaller pieces:
Find all the records where the score is reset. Let's call this subquery the resetRecords.
Join the records of the original table to the resetRecords, such that every record has "its" reset record (i.e., the reset record that provides the base for its count).
Use ROW_NUMBER() OVER (PARTITION BY ... ) to assign the numbers.
Try to do this one step at a time. Beware: It won't be a simple query, so a solution with temp tables or cursors might be easier to understand and maintain.
Try something like this:
with x as (
select *, sum(case when Score=0 then 1 else 0 end) over(order by ScoreDate) as grp
from ScoreDetails
)
select ScoreDate, Score, row_number() over (partition by grp order by ScoreDate)
from x
order by ScoreDate
(as soon as a zero is encountered in score column, it resets to 1 and then start again, you said)

Using a While Loop to update a field by 1 each time a value changes

So I have a table that has two records that need to be one. I can identify them but I want to update them in groups (sort of like a scan update =1, then proceed, then some other field changes, increment the number by 1 and proceed.)
Example table:
IDEvent 1 2 3 4 5
Col1 1 1 0 1 0
Col2 a a b a b
So essentially, my outcome would look like this afterwards so that I can write a select and group by col1 to then group the two first records into one but leave non consecutive record alone. I tried while loops but I couldn't figure it out.
IDEvent 1 2 3 4 5
Col1 1 1 0 2 0
Col2 A A B A B
alter view PtypeGroup as
WITH q AS
(
SELECT *,
ROW_Number() OVER (PARTITION BY idsession, comment ORDER BY ideventrecord) AS rnd,
ROW_NUMBER() OVER (PARTITION BY idsession ORDER BY ideventrecord) AS rn
FROM [ratedeventssorted]
)
SELECT min(ideventrecord) as IDEventRecord, idsession, min(distancestamp) as distancestamp, sum(length) as length, min(comment) as comment2, min(eventscorename) as firstptype, min(eventscoredescription) as Ptype2,
MIN(ideventrecord) AS first_number,
MAX(ideventrecord) AS last_number,
comment
,COUNT(ideventrecord) AS numbers_count
--into test
FROM q
where eventscorename IN ('Flex', 'Chpsl')
GROUP BY idsession,
rnd - rn,
comment

Applying grouped ranking using ROW_NUMBER

I m Looking for ways to assign the row numbers as below for the table
Roll No Name Score
1 ABC 10
1 ABC 10
1 DEF 8
2 ASC 9
2 YHN 4
3 IOP 5
3 YHN 4
I m looking for a way to assign the roll no as Rownumber()
Roll No Name Score Row_Number
1 ABC 10 1
1 ABC 10 2
1 DEF 8 3
2 ASC 9 1
2 YHN 4 2
3 IOP 5 1
3 YHN 4 2
I m trying to work around with Row_number() , it is isnt working . ANy inputs on this world be great :)
Thanks !!!!
SELECT [Roll No], Name, Score, [ROW_NUMBER] =
ROW_NUMBER() OVER (PARTITION BY [Roll No] ORDER BY Score DESC)
FROM dbo.table
ORDER BY [Roll No], [ROW_NUMBER];
If you later decide that you want to handle ties in a different way, play with using RANK() or DENSE_RANK() in place of ROW_NUMBER()...

SUM of MAX(TOP x)

Say I have a table like the following:
PK Code Value
1 A 200
2 A 300
3 A 25
4 A 75
5 A 50
6 A 15
7 A 300
8 A 75
How would I get the value of the top 4 highest values where code=A (i.e. just want the sum of 300 + 300 + 200 + 75)
Thanks
You can use a derived table or Common Table Expression to get the top 4 then SUM that.
SELECT SUM(Value) As Top4Sum
FROM
(
SELECT TOP (4) Value
FROM YourTable
WHERE Code = 'A'
ORDER BY Value DESC
) T
If you wanted the SUM of the TOP 4 for every Code you could do
;WITH CTE
AS (SELECT *,
ROW_NUMBER() OVER (PARTITION BY Code ORDER BY Value DESC) RN
FROM YourTable)
SELECT Code,
SUM(Value)
FROM CTE
WHERE RN <= 4
GROUP BY Code

Resources