How to add sequence number to group of rows based on status column - sql

I have a group of rows in order. Column "Status" has only two value 0/1. Now, I'd like to add a sequence number / group number for each 0/1 set. there can be 1 to many rows of 0's but only one 1 for each set in the end. How do I add a new column as sequence number that only increases when there is a 1.
example:
ID Status Row Group Number
1 0 1
2 0 1
3 1 1
4 0 2
5 1 2
6 0 3
7 0 3
8 0 3
9 1 3
question is how do I get the third column?
thank you.

Hmmm . . . This is a cumulative sum up to the previous row (plus 1). So, in SQL Server 2012+, you can do:
select t.*,
1 + sum(status) over (order by id) - status as rowgroupnumber
from t;

Related

SQL Get max value of n next rows

Say I have a table with two columns: the time and the value. I want to be able to get a table with :
for each time get the max values of every next n seconds.
If I want the max value of every next 3 seconds, the following table:
time
value
1
6
2
1
3
4
4
2
5
5
6
1
7
1
8
3
9
7
Should return:
time
value
max
1
6
6
2
1
4
3
4
5
4
2
5
5
5
5
6
1
3
7
1
7
8
3
NULL
9
7
NULL
Is there a way to do this directly with an sql query?
You can use the max window function:
select *,
case
when row_number() over(order by time desc) > 2 then
max(value) over(order by time rows between current row and 2 following)
end as max
from table_name;
Fiddle
The case expression checks that there are more than 2 rows after the current row to calculate the max, otherwise null is returned (for the last 2 rows ordered by time).
Similar Version to Zakaria, but this solution uses about 40% less CPU resources (scaled to 3M rows for benchmark) as the window functions both use the same exact OVER clause so SQL can better optimize the query.
Optimized Max Value of Rolling Window of 3 Rows
SELECT *,
MaxValueIn3SecondWindow = CASE
/*Check 3 rows exists to compare. If 3 rows exists, then calculate max value*/
WHEN 3 = COUNT(*) OVER (ORDER BY [Time] ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING)
/*Returns max [Value] between the current row and the next 2 rows*/
THEN MAX(A.[Value]) OVER (ORDER BY [Time] ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING)
END
FROM #YourTable AS A

SQL get count of value

I have the following table. Now I want to count the amount of each value in this table.
value
count
1
1
-1
1
2
1
3
1
-1 and 1 should be seen as 1, so the output should be
value
count
1
2
2
1
3
1
Does someone know a quick fix?
Grouping by value, and making such values the absolute value so you ignore the negative sign:
SELECT
ABS(VALUE) VALUE, COUNT() COUNT
FROM
table
GROUP BY
ABS(VALUE)

Finding adjacent column values from the last non-null value of a certain column in Snowflake (SQL) using partition by

Say I have the following table:
ID
T
R
1
2
1
3
Y
1
4
1
5
1
6
Y
1
7
I would like to add a column which equals the value from column T based on the last non-null value from column R. This means the following:
ID
T
R
GOAL
1
2
1
3
Y
1
4
Y
3
1
5
4
1
6
Y
4
1
7
6
I do have many ID's so I need to make use of the OVER (PARTITION BY ...) clause. Also, if possible, I would like to use a single statement, like
SELECT *
, GOAL
FROM TABLE
So without any extra select statement.
T is in ascending order so just null it out according to R and take the maximum looking backward.
select *,
max(case when R is not null then T end)
over (
partition by id
order by T
rows between unbounded preceding and 1 preceding
) as GOAL
from TBL
http://sqlfiddle.com/#!18/c927a5/5

Create a column with Conditional Recursive SQL / based on a condition

Consider the table ordered by id with column IsSatisfied.
ID
IsSatisfied
1
0
2
1
3
0
4
0
5
1
6
0
....
...
I would like to create another column State, that initially takes value 0 and changes it between 0 and 1, only when the value of Isatisfied is equal to 1, as in the table below.
ID
IsSatisfied
State
1
0
0
2
1
1
3
0
1
4
0
1
5
1
0
6
0
0
....
...
...
I tried LAG() function or recursive CTE, but unfortunately failed.
The closest solution that I have found is Conditional Recursive SQL Select, but I was not able to convert it to suit my needs.
If I understand correctly, you want a cumulative sum of issatisfied -- and then the remainder when divided by 2:
select t.*,
( sum(issatisfied) over (order by id) % 2 ) as state
from t;

Resetting a Count in SQL

I have data that looks like this:
ID num_of_days
1 0
2 0
2 8
2 9
2 10
2 15
3 10
3 20
I want to add another column that increments in value only if the num_of_days column is divisible by 5 or the ID number increases so my end result would look like this:
ID num_of_days row_num
1 0 1
2 0 2
2 8 2
2 9 2
2 10 3
2 15 4
3 10 5
3 20 6
Any suggestions?
Edit #1:
num_of_days represents the number of days since the customer last saw a doctor between 1 visit and the next.
A customer can see a doctor 1 time or they can see a doctor multiple times.
If it's the first time visiting, the num_of_days = 0.
SQL tables represent unordered sets. Based on your question, I'll assume that the combination of id/num_of_days provides the ordering.
You can use a cumulative sum . . . with lag():
select t.*,
sum(case when prev_id = id and num_of_days % 5 <> 0
then 0 else 1
end) over (order by id, num_of_days)
from (select t.*,
lag(id) over (order by id, num_of_days) as prev_id
from t
) t;
Here is a db<>fiddle.
If you have a different ordering column, then just use that in the order by clauses.