One record from multiple records in the table - sql

I have a scenario where ID has three flags.
For example
ID flag1 flag2 flag3
1 0 1 0
2 1 0 0
1 1 0 0
1 0 0 1
2 0 1 0
3 0 1 0
4 1 0 0
Now I want the records having flag2=1 only.. I.e ID=3 has flag2=1 where as ID = 1 and 2 has flag1 and flag3 =1 along with flag2=1. I don't want ID=1 and 2.
I can't make ID unique or primary. I tried with case when statements but it I am somehow missing the basic logic.
We can do it with CTE but I want to repeat this for three different scenarios(Same logic I want to repeat for ID=4 where Flag1=1 only).

You can get the ids with this condition using group by and having:
select id
from table t
group by id
having min(flag2) = max(flag2) and min(flag2) = 1;

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;

How to check the count of each values repeating in a row

I have two tables. Data in the first table is:
ID Username
1 Dan
2 Eli
3 Sean
4 John
Second Table Data:
user_id Status_id
1 2
1 3
4 1
3 2
2 3
1 1
3 3
3 3
3 3
. .
goes on goes on
These are my both tables.
I want to find the frequency of individual users doing 'status_id'
My expected result is:
username status_id(1) status_id(2) status_id(3)
Dan 1 1 1
Eli 0 0 1
Sean 0 1 2
John 1 0 0
My current code is:
SELECT b.username , COUNT(a.status_id)
FROM masterdb.auth_user b
left outer join masterdb.xmlform_joblist a
on a.user1_id = b.id
GROUP BY b.username, b.id, a.status_id
This gives me the separate count but in a single row without mentioning which status_id each column represents
This is called pivot and it works in two steps:
extracts the data for the specific field using a CASE statement
aggregates the data on users, to make every field value lie on the same record for each user
SELECT Username,
SUM(CASE WHEN status_id = 1 THEN 1 END) AS status_id_1,
SUM(CASE WHEN status_id = 2 THEN 1 END) AS status_id_2,
SUM(CASE WHEN status_id = 3 THEN 1 END) AS status_id_3
FROM t2
INNER JOIN t1
ON t2.user_id = t1._ID
GROUP BY Username
ORDER BY Username
Check the demo here.
Note: This solution assumes that there are 3 status_id values. If you need to generalize on the amount of status ids, you would require a dynamic query. In any case, it's better to avoid dynamic queries if you can.

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.

Compare 2 tables and update final table with the row which has max value Bigquery

I have two tables TableA and Final_Table
TableA
ID Step1 Step2 Step3 Step4
1 1 1 0 0 --Update Final_table for Id1 with these values as more steps have 1
2 1 1 1 0
3 1 1 1 1 --Since 3 doesn't exist in Final table insert row in final table
Final_Table
ID Step1 Step2 Step3 Step4
1 1 0 0 0
2 1 1 1 1 --Keep this as more steps have 1 in it
4 0 0 0 0 --since Id4 doesn't exist in Table
After Running the Query I want the final_table to look like below
Final_Table
ID Step1 Step2 Step3 Step4
1 1 1 0 0
2 1 1 1 1
3 1 1 1 1
4 0 0 0 0
Whenever a Id exists in both table I want to Update the Final_Table with data which has max steps as 1. I would appreciate any help!Thanks in advance
I used Merge and Update to solve my question - It worked liked a charm. I created a sumT column of all steps in my Final_Table. Might help someone
First query:
MERGE final_Table T
USING (SELECT id, SUM(of all columns) AS sumA
FROM TableA
GROUP BY Id FROM TableA) S ON T.id = S.id
WHEN MATCHED THEN
UPDATE SET sum = greatest(sumA, sumT)
WHEN NOT MATCHED THEN
INSERT (id, sumT) VALUES (id,sumA)
Second query:
UPDATE Final_Table AS 1 OR 0 depending on SumT
Hope it helps!

Grouping multiple counts with each row representing one ID

I have a table that logs activity. It has an int activity column that indicates what type of activity it was and a corresponding admin_id that indicates which admin performed the action. Each row in the table represents one action, so for example, an administrator would cancel a user's account, and a row with that admin's id and activity=[int representing cancel] would be created. I need a way to a select a result which groups each admin's activity such that the row corresponding to the admin would have the # of each activity
The result would look like
admin_id | numActivated | numCanceled | numRenewed
1 1 1 2
2 1 3 0
With numActivated, numCanceled, and numRenewed all coming from the count for each activity.
This is what the original table would have looked like:
admin_id | activity ...
1 2
1 1
1 3
1 3
2 2
2 2
2 2
2 1
(activity 1: activate, 2: cancel, 3: renew)
Thanks
This should do what you're asking for:
select admin_id,
sum(case when activity = 1 then 1 else 0 end) as numActivated,
sum(case when activity = 2 then 1 else 0 end) as numCanceled,
sum(case when activity = 3 then 1 else 0 end) as numRenewed
from YourTable
group by admin_id
This should do it:
SELECT
T.admin_id,
sum(T.activate) AS numActivated,
sum(T.canceled) AS numCanceled,
sum(T.renew) AS numRenewed
FROM (
SELECT
admin_id,
CASE activity WHEN 1 THEN 1 ELSE 0 END AS activate,
CASE activity WHEN 2 THEN 1 ELSE 0 END AS canceled,
CASE activity WHEN 3 THEN 1 ELSE 0 END AS renew
FROM Table
) AS T
GROUP BY T.admin_id