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

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;

Related

How to reset running counts and start from 1 based on the condition and make previous row values as 0 in SQL?

For example there is some table with below data:
No Id Value
1 100 1
2 100 0
3 100 1
4 100 2
1 101 1
2 101 2
1 102 0
2 102 1
I have to write SQL query, which will return row count based on specific condition. If the value matches 0 then need to reset running counts and start from 1 and make previous row values as 0
So the result will be like:
No Id Value Running Count
1 100 1 0
2 100 0 0
3 100 1 1
4 100 1 2
1 101 1 1
2 101 2 2
1 102 1 0
2 102 0 0
Your sample dataset is quite limited so I'm not sure of all edge cases but see if the following works for you. If not it might help get you there.
This gets a running count using a window & case expression and uses lead to check the next value.
If the current value or next value is 0 the count is 0, otherwise it's the running count subtracting 1 if there is a 0 in the Id block indicating the count was reset.
select No, Id, Value,
case when value = 0 or nv = 0
then 0
else
rc - case when Min(value) over(partition by id) = 0 then 1 else 0 end
end Running_Count
from (
select *,
Sum(case when value = 0 then 0 else 1 end) over(partition by id order by no) rc,
Lead(Value) over(partition by Id order by No)nv
from t
)t;

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.

In Flink, how to convert the cumulative value into an incremental value in flink and then aggregate by some keys

How to convert the cumulative value into an incremental value in flink (some keys are considered to be a user, and then the cumulative value becomes the incremental value of two adjacent ones), and then on the basis of the incremental value (time Dimension, a key) for aggregation (sum)
For example, origin data is:
time A B value
0 1 1 1
0 2 2 2
0 1 1 4
0 2 2 3
1 1 1 5
1 2 2 6
After convert to incremental value, we got
time A B value
0 1 1 1
0 2 2 2
0 1 1 3
0 2 2 1
1 1 1 2
1 2 2 3
Then we aggregate by (time, A), got final result is
time A value
0 1 4
0 2 3
1 1 2
1 2 3
Is there a program that can do these two things at once?
One solution is to use session window or global window to convert the original table into an incremental table and store it in another place, and start another task to aggregate the results? But this will consume additional storage.
Sorry for my poor english and thanks for your advice.
There's no need to have two separate applications, or to store anything. Just let the output of the first step flow into the second step. Conceptually that's
results = input
.somehowDoTheIncrementalPart()
.thenAggregate();
or in SQL you could use a nested query, something like
SELECT ts, sum(diff) FROM (
SELECT ts, userId, diff
FROM events
MATCH_RECOGNIZE (
PARTITION BY id
ORDER BY ts
MEASURES
p2.v - p1.v AS diff, p2.id AS userId, p2.ts AS ts
AFTER MATCH SKIP TO LAST p2
PATTERN (p1 p2)
DEFINE p1 AS TRUE, p2 AS TRUE )
) GROUP BY ts, userId

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

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;

Inserting a new indicator column to tell if a given row maximizes another column in SQL

I currently have a table in SQL that looks like this
PRODUCT_ID_1 PRODUCT_ID_2 SCORE
1 2 10
1 3 100
1 10 3000
2 10 10
3 35 100
3 2 1001
That is, PRODUCT_ID_1,PRODUCT_ID_2 is a primary key for this table.
What I would like to do is use this table to add in a row to tell whether or not the current row is the one that maximizes SCORE for a value of PRODUCT_ID_1.
In other words, what I would like to get is the following table:
PRODUCT_ID_1 PRODUCT_ID_2 SCORE IS_MAX_SCORE_FOR_ID_1
1 2 10 0
1 3 100 0
1 10 3000 1
2 10 10 1
3 35 100 0
3 2 1001 1
I am wondering how I can compute the IS_MAX_SCORE_FOR_ID_1 column and insert it into the table without having to create a new table.
You can try like this...
Select PRODUCT_ID_1, PRODUCT_ID_2 ,SCORE,
(Case when b.Score=
(Select Max(a.Score) from TableName a where a.PRODUCT_ID_1=b. PRODUCT_ID_1)
then 1 else 0 End) as IS_MAX_SCORE_FOR_ID_1
from TableName b
You can use a window function for this:
select product_id_1,
product_id_2,
score,
case
when score = max(score) over (partition by product_id_1) then 1
else 0
end as is_max_score_for_id_1
from the_table
order by product_id_1;
(The above is ANSI SQL and should run on any modern DBMS)