Dense Rank grouping by IDs - sql

I am having trouble getting my DENSE_RANK() function in Oracle to work how I would like. First, my dataset:
ID DATE
1234 01-OCT-2020
1234 01-OCT-2021
1234 01-OCT-2022
2345 01-APR-2020
2345 01-APR-2021
2345 01-APR-2022
I am trying to use the dense rank function to return results with a sequence number based on the DATE field, and grouping by ID. How I want the data to return:
ID DATE SEQ
1234 01-OCT-2020 1
1234 01-OCT-2021 2
1234 01-OCT-2022 3
2345 01-APR-2020 1
2345 01-APR-2021 2
2345 01-APR-2022 3
The query I have so far:
SELECT ID, DATE, DENSE_RANK() Over (order by ID, DATE asc) as SEQ
However, this returns incorrectly as the sequence number will go to 6 (Like its disregarding my intentions to sequence based on the DATE field within a certain ID). If anyone has any insights into how to make this work it would be very much appreciated!

You want row_number():
select id, date, row_number() over (partition by id order by date) as seq
You could actually use dense_rank() as well, if you want duplicates to have the same idea. The key idea is partition by.

Related

Select the latest NEW rows by Date from the Snapshot Table

I have a snapshot table like the following
id
name
value
date
123
ABC Corp
500
yesterday
123
ABC Corp
500
today
456
XYZ Ltd.
700
today
123
ABC Corp
500
tomorrow
456
XYZ Ltd.
700
tomorrow
789
PQR Consulting
100
tomorrow
I would like to get the new rows only like the following table from the above snapshot table using sql
id
name
value
date
456
XYZ Ltd.
700
today
789
PQR Consulting
100
tomorrow
I need a pointer whether to follow the window function (like LAG() etc.) to get the new table. or more simple solution is there? Thanks in advance!
There are a few options here, one of them is to use a cte or a derived table to add row_number based on the date column to the table, and the other is to use first_value window function. I'm pretty sure the derived table solution would be better in terms of performance, but I don't have the time to test.
Here's what I would do:
;WITH cte AS
(
SELECT id, name, value, date, ROW_NUMBER() OVER(PARTITION BY id ORDER BY date DESC) as rn
FROM snapshotTable
)
SELECT id, name, value, date
FROM cte
WHERE rn = 1;
To get the earliest records all you need to do is remove the DESC from the order by clause.

Running Count of Unique Identifier Occurrences in SQL

So I'm trying to get a running count of uses over time by a unique identifier,
E.G.
Date UniqueID Running Count
1/1/2019 234567 1
1/1/2019 123456 1
1/2/2019 234567 2
1/3/2019 234567 3
1/3/2019 123456 2
Basically I want to be able to see that on 1/3/2019 that was the 3rd time that UniqueID 234567 showed up in the data.
I tried:
SELECT Date, UniqueID,
count(UniqueID) OVER (ORDER BY Date, UniqueID rows unbounded preceding) AS RunningTotal
but this just does a overall running total, so it doesn't reset with a new UniqueID
SELECT Date, UniqueID, count(UniqueID) OVER (ORDER BY Date, UniqueID rows unbounded preceding) AS RunningTotal
Is there anything I could do to make it reset for each UniqueID
Assuming that the 2 in the last row is a typo, you want either ROW_NUMBER() or DENSE_RANK():
SELECT Date, UniqueID,
ROW_NUMBER(UniqueID) OVER (PARTITION BY UniqueID ORDER BY Date) AS RunningTotal
You would use DENSE_RANK() if you could have duplicates on one day that you wanted to count only once.
By the way, you could also express this using COUNT(*):
SELECT Date, UniqueID,
COUNT(*) OVER (PARTITION BY UniqueID ORDER BY Date) AS RunningTotal
There are some subtle differences in the handling of duplicate values. Normally, COUNT() is not used for this purpose because the ranking functions are so pervasive (and useful).

Increase number if row value duped

Sorry not sure how to example this by using words (that's why have an issue to find an answer)
I need that Sequence will increase the number if ID value is duped
ID Sequence Value
1111 0 234324
2222 0 23432
3333 0 324
3333 1 234
3333 2 432234
4444 0 23423
4444 1 234
If you want to start from 0, use this query:
select *, ROW_NUMBER()over( partition by id order by id)-1 from tbl
You want row_number(). Something like this:
select t.*,
row_number() over (partition by id order by id) as seqnum
from t;
Note: the numbers will be incrementing, but the rows will not be in any particular order.
SQL tables represent unordered sets. You data has no obvious ordering. You can change the order by to get values in a particular order for a given id.

SQL Query - Design struggle

I am fairly new to SQL Server (2012) but I was assigned the project where I have to use it.
The database consists of one table (counted in millions of rows) which looks mainly like this:
Number (float) Date (datetime) Status (nvarchar(255))
999 2016-01-01 14:00:00.000 Error
999 2016-01-02 14:00:00.000 Error
999 2016-01-03 14:00:00.000 Ok
999 2016-01-04 14:00:00.000 Error
888 2016-01-01 14:00:00.000 Error
888 2016-01-02 14:00:00.000 Ok
888 2016-01-03 14:00:00.000 Error
888 2016-01-04 14:00:00.000 Error
777 2016-01-01 14:00:00.000 Error
777 2016-01-02 14:00:00.000 Error
I have to create a query which will show me only the phone numbers (one number per row so probably Group by number?) that meet the conditions:
Number reappears at least 3 times
Last two times (that has to be based on date; originally records are not sorted by date) has to be an Error
For example, in the table above the phone number that meets the criteria is only 888, beacuse for 999 2nd newest status is Ok and number 777 reoccurs only 2 times.
I will appreciate any kind of help!
Thanks in advance!
You can use row_number() and conditional aggregation:
select number
from (select t.*,
row_number() over (partition by number order by date desc) as seqnum
from t
) t
group by number
having count(*) >= 3 and
max(case when seqnum = 1 then status end) = 'Error' and
max(case when seqnum = 2 then status end) = 'Error';
Note: float is a really, really bad type to use for the "number" column. In particular, two numbers can look the same but differ in low-order bits. They will produce different rows in the group by.
You should probably use varchar() for telephone numbers. That gives you the most flexibility. If you need to store the number as a number, then decimal/numeric is a much, much better choice than float.
select *, ROW_NUMBER() OVER(partition by Number, order by date desc) as times
FROM
(
select Number, Date
From table
where Number in
(
select Number
from table
group by Number
having count (*) >3
) as ABC
WHERE ABC.times in (1,2) and ABC.Status = 'Error'
with CTE as
(
select t1.*, row_number() over(partition by t1.Number order by t1.date desc) as r_ord
from MyTable t1
)
select C1.*
from CTE C1
inner join
(
select Number
from CTE
group by Number
having max(r_ord) >=3
) C2
on C1.Number = C2.Number
where C1.r_ord in (1,2)
and C1.Status = 'Error'

How can I update a group of accounts where unique identifier is not an Int (SQL)

Below is my table and the column I'm trying to update is the planID
AccountUsageID AccountID PLanID
38dkaie 1234 1
38d246e 1234 1
38dka41 1234 1
38dA38e 1234 1
3AKkaie 1234 1
3854E6e 1234 1
AEdka41 1234 1
IRKMdAe 1234 1
There are 8 accounts total and I want to update the planID to 1,2,3, in group of 2 account usuage per plan.
The final result should look like:
AccountUsageID AccountID PLanID
38dkaie 1234 1
38d246e 1234 1
38dka41 1234 2
38dA38e 1234 2
3AKkaie 1234 3
3854E6e 1234 3
AEdka41 1234 4
IRKMdAe 1234 4
Can someone please help?
You can do this with the ROW_NUMBER() function and some modulus division:
;with cte AS (SELECT *,ROW_NUMBER() OVER(PARTITION BY AccountID ORDER BY [Account Usage]) RN
FROM TAble1
)
UPDATE cte
SET PlanID = (RN-(RN-1)%2)/2+1
Demo: SQL Fiddle
This will ensure no more than 2 records per combination of PLANID and ACCOUNTID. You can remove the PARTITION BY AccountID if you don't want PLANID to repeat for different ACCOUNTID values, likewise you can alter the ORDER BY [Account Usage] to suit your preferences.
The ROW_NUMBER() function assigns a number to each row. PARTITION BY is optional, but used to start the numbering over for each value in that group, ie: if you PARTITION BY Some_Date then for each unique date value the numbering would start over at 1. ORDER BY of course is used to define how the counting should go, and is required in the ROW_NUMBER() function.
Update: You can adjust the number of items per set by simply changing the integer used in the modulus and division step, and you can test the results before performing the update by selecting it first:
;with cte AS (SELECT *,ROW_NUMBER() OVER(PARTITION BY AccountID ORDER BY [Account Usage]) RN
FROM TAble1
)
SELECT [Account Usage],AccountID, PlanID = (RN-(RN-1)%30)/30+1
FROM cte