oracle - no partition in window function but fill sequential numbers for acd properties - sql

I have acd properties table with 3 columns - id, acd and rpt. The rpt is set to 1 when it is first reported for the acd property, but if any consequent acd properties are repeating, it is set to 0. The id column is always incrementing (sort of pk). Now for the continous zeros, I need the sequential numbers starting from 2,3... as shown in the wanted column.
id acd rpt wanted
1 a 1 1
2 b 1 1
3 b 0 2
4 a 1 1
5 a 0 2
6 a 0 3
7 d 1 1
8 d 0 2
9 d 0 3
10 c 1 1
11 c 0 2
12 c 0 3
13 c 0 4
14 c 0 5
15 d 1 1
16 a 1 1
I tried the window function, but when I use "value" column in partition clause it is grouping all a's which is not desired. Is it possible to get the results as in "wanted" column given rpt and id incrementing.

When rpt = 1, then you want 1. Then you want the 0s enumerated for each acd. If this is correct, then the logic is:
select t.*,
(case when rpt = 1 then 1
else 1 + row_number() over (partition by acd, rpt order by id)
end) as wanted
from t;

You need nested OLAP-funtions:
SELECT dt.*,
Row_Number() Over (PARTITION BY grp ORDER BY id)
FROM
( -- calculate a group number using a Cumulative Sum over 0/1 (for partitioning in next step)
SELECT prop.*, Sum(rpt) Over (ORDER BY id ROWS Unbounded Preceding) AS grp
FROM prop
) dt

Related

Number of Rows Between Polarity Changes SQL

I want to count the number of rows between polarity changes grouped by id in SQL. I'm thinking that there may be a clever way to use window functions to get the job done but I don't know what it is.
Consider data like this:
id
polarity
date
1
0
12/1
1
1
12/2
1
0
12/3
1
0
12/4
1
1
12/5
2
0
12/1
2
0
12/2
2
0
12/3
2
1
12/4
2
0
12/5
2
0
12/6
2
0
12/7
2
1
12/8
Is there a way to count the number of rows between each change in polarity to get something like this :
id
n
1
1
1
2
2
3
2
3
You can do:
select id, count(*) as n
from (
select *,
sum(i) over(partition by id order by date) as g
from (
select *, case when polarity <> lag(polarity)
over(partition by id order by date)
then 1 else 0 end as i
from t
) x
) y
group by id, g
having max(polarity) = 0

Creating duplicating rank over multiple columns

I have data as below where for one customer ID there are several orders (KEY) which is the primary key. I have also have a activity flag as below (either 0 or 1).
CUST_ID KEY FLAG
1 1 1
1 2 1
1 3 1
1 4 0
1 5 0
1 6 1
1 7 1
1 8 0
1 9 0
Now I want to create ranks as below based on the FLAG. The idea is to give same Rank as preceding row if the FLAG is same as preceding row. The Rank increments if the current value is different from preceding value.
CUST_ID KEY FLAG RN
1 1 1 1
1 2 1 1
1 3 1 1
1 4 0 2
1 5 0 2
1 6 1 3
1 7 1 3
1 8 0 4
1 9 0 4
I'm new to SQL, so please let me know if I need to reframe my question.
Use LAG() window function to get each row's previous flag and then use SUM() window function to create the rankings:
SELECT CUST_ID, KEY, FLAG,
SUM(CASE WHEN FLAG <> prev_FLAG THEN 1 END) OVER (PARTITION BY CUST_ID ORDER BY KEY) RN
FROM (
SELECT *, LAG(FLAG, 1, FLAG - 1) OVER (PARTITION BY CUST_ID ORDER BY KEY) prev_FLAG
FROM tablename
) t;
See the demo.
The code could be simplified, depending on the specific database that you use.

Order a column by pair of values

I have 2 simple columns:
one column is simply an ID column and the other column is some sort of boolean type column.
ID V
0 1
1 0
2 0
3 1
4 1
5 0
I want to order the rows by pair of values (0,1) of column V
(while still keeping the ID as minimal as possible):
ID V
1 0
0 1
2 0
3 1
5 0
4 1
How do I do that ?
Seems you want get rows for 0 and 1 in turn:
select id, v
from tab
order by
row_number()
over (partition by v
order by id)
,v

Is there a way to group this data?

Data Looks like -
1
2
3
1
2
2
2
3
1
5
4
1
2
So whenever there is a 1, it marks the beginning of a group which includes all the elements until it hits the next 1. So here,
1 2 3 - group 1
1 2 2 2 3 - group 2
and so on..
What would be the SQL query to show the average for every such group.
I could not figure out how to group them without using for loops or PLSQL code.
Result should look like two columns, one with the actual data and col 2 with the average value-
1 - avg value of 1,2 3
2
3
1 - avg value of 1,2,2,2,3
2
2
2
3
1 - avg value of 1,5,4
5
4
1 - avg value of 1,2
2
SQL tables represent unordered sets. There is no ordering, unless a column specifies the ordering. Let me assume that you have such a column.
You can identify the groups using a cumulative sum:
select t.*,
sum(case when t.col = 1 then 1 else 0 end) over (order by ?) as grp
from t;
? is the column that specifies the ordering.
You can then calculate the average using aggregation:
select grp, avg(col)
from (select t.*,
sum(case when t.col = 1 then 1 else 0 end) over (order by ?) as grp
from t
) t
group by grp;

Increment Row Number on Group

I am working on a query for SQL Server 2005 that needs to return data with two 'index' fields. The first index 't_index' should increment every time the 'shade' column changes, whilst the second index increments within the partition of the values in the 'shade' column:
t_index s_index shade
1 1 A
1 2 A
1 3 A
1 4 A
1 5 A
2 1 B
2 2 B
2 3 B
2 4 B
2 5 B
To get the s_index column I am using the following:
Select ROW_NUMBER() OVER(PARTITION BY [shade] ORDER BY [shade]) as s_index
My question is how to get the first index to only increment when the value in the 'shade' column changes?
That can be accomplished with the DENSE_RANK() function:
DENSE_RANK() OVER(Order By [shade]) as t_index
You can try to use DENSE_RANK() for that:
SELECT
shade,
s_index = ROW_NUMBER() OVER(PARTITION BY [shade] ORDER BY [shade]),
t_index = DENSE_RANK() OVER (ORDER BY [shade])
FROM dbo.YourTableNameHEre
Gives output:
shade s_index t_index
A 1 1
A 2 1
A 3 1
A 4 1
A 5 1
B 1 2
B 2 2
B 3 2
B 4 2
B 5 2