case expression with count and condition of count is greater then - sql

I have the below table
Table A
PK status_cd id grp grp_rnk_asc grp_rnk_desc action_dt
154 new 10 1 1 4 11/6/2019
154 pending 10 1 2 3 11/7/2019
154 pending 10 1 3 2 11/8/2019
154 approved 10 1 4 1 11/9/2019
I want to...
Count partition with condition and when that count is > then 1 then 'pass'
Then be able to add additional when to the case expression
For example:
Sample of criteria
select
Count when status_cd not in ('new','approved')
over (partition by id,grp order by action_dt) if that count > 1 then 'pass'
--also be able to add new conditions here...
from A
--no where clause

I think you want:
select (case when sum(case when tatus_cd not in ('new',' approved') then 1 else 0 end) over (partition by id, grp) > 1
then 'pass'
end)
from A

Related

Get users that have at least one product code and also more than 10 of the other product code

The table that needs to be queried looks like this:
ID
UserID
ProductCodes
1
33
9999
2
456
3051
3
456
9999
4
456
3051
4
33
9999
How would I write a SQL query to find out which users have at least one productCodes = '9999' and also have more than 10 productCodes <> '9999'?
You can use GROUP BY and HAVING:
SELECT
UserID
FROM dbo.YourTable
GROUP BY
UserId
HAVING SUM(CASE WHEN ProductCodes = '9999' THEN 1 ELSE 0 END) >= 1
AND COUNT(DISTINCT ProductCodes) >= 11
;
Use Case or Intersect (case is more performant)
SELECT UserID, SUM (case when ProductCodes='9999' then 1 else 0 end) PC9999
, SUM (case when ProductCodes<>'9999' then 1 else 0 end) PCNot9999
FROM dbo.Users
WHERE ProductCodes='9999'
GROUP BY UserID
HAVING SUM (case when ProductCodes='9999' then 1 else 0 end)>0
AND SUM (case when ProductCodes<>'9999' then 1 else 0 end) >10
I ended up going with this. It allows us to get specific with how many times a '9999' product code has been used in comparison with other codes.
SELECT
UserID
FROM Session_Hst
GROUP BY
UserID
HAVING SUM(CASE WHEN ProductCodes = '9999' THEN 1 ELSE 0 END) >= 1
AND COUNT(CASE WHEN ProductCodes <> '9999' THEN 1 ELSE null END ) >= 10
;

how to set auto increment column value with condition

I have table like this:
value nextValue
1 2
2 3
3 20
20 21
21 22
22 23
23 NULL
Value is ordered ASC, nextValue is next row Value.
requirement is group by with condition nextValue-value>10, and count how many values in different groups.
For example, there should be two groups (1,2,3) and (20,21,22,23), first group count is 3, the second group count is 4.
I'm trying to mark each group with unique number, so I could group by these marked nums
value nextValue mark
1 2 1
2 3 1
3 20 1
20 21 2
21 22 2
22 23 2
23 NULL 2
But I don't know how to write mark column, I need an autocrement variable when nextValue-value>10.
Can I make it happen in Hive? Or there's better solution for the requirement?
If I understand correctly, you can use a cumulative sum. The idea is to set a flag when next_value - value > 10. This identifies the groups. So, this query adds a group number:
select t.*,
sum(case when nextvalue > value + 10 then 1 else 0 end) over (order by value desc) as mark
from t
order by value;
You might not find this solution satisfying, because the numbering is in descending order. So, a bit more arithmetic fixes that:
select t.*,
(sum(case when nextvalue > value + 10 then 1 else 0 end) over () + 1 -
sum(case when nextvalue > value + 10 then 1 else 0 end) over (order by value desc)
) as mark
from t
order by value;
Here is a db<>fiddle.
Calculate previous value, then calculate new_group_flag if value-prev_value >10, then calculate cumulative sum of new_group_flag to get group number (mark). Finally you can calculate group count using analytics function or group-by (in my example analytics count is used to show you the full dataset with all intermediate calculations). See comments in the code.
Demo:
with your_data as (--use your table instead of this
select stack(10, --the number of tuples generated
1 ,
2 ,
3 ,
20 ,
21 ,
22 ,
23 ,
40 ,
41 ,
42
) as value
)
select --4. Calculate group count, etc, etc
value, prev_value, new_group_flag, group_number,
count(*) over(partition by group_number) as group_count
from
(
select --3. Calculate cumulative sum of new group flag to get group number
value, prev_value, new_group_flag,
sum(new_group_flag) over(order by value rows between unbounded preceding and current row)+1 as group_number
from
(
select --2. calculate new_group_flag
value, prev_value, case when value-prev_value >10 then 1 else 0 end as new_group_flag
from
(
select --1 Calculate previous value
value, lag(value) over(order by value) prev_value
from your_data
)s
)s
)s
Result:
value prev_value new_group_flag group_number group_count
1 \N 0 1 3
2 1 0 1 3
3 2 0 1 3
20 3 1 2 4
21 20 0 2 4
22 21 0 2 4
23 22 0 2 4
40 23 1 3 3
41 40 0 3 3
42 41 0 3 3
This works for me
It needs "rows between unbounded preceding and current row" in my case.
select t.*,
sum(case when nextvalue > value + 10 then 1 else 0 end) over (order by value desc rows between unbounded preceding and current row) as mark
from t
order by value;

How do I find corresponding row data based on max column values?

I want to take the max value of each partitioned block and find the correlating id(in the same row). I then want to use the singular show_id as the 'winner' and bool_flag all rows in the same partition with a matching show_id.
I am having trouble implementing this, especially the window function-- I have hit multiple issues saying that the subquery is not supported, or "must appear in the GROUP BY clause or be used in an aggregate function sql"
subQ1 as (
select subQ0.*,
case
**when show_id =
(select id from (select show_id, max(rn_max_0)
over (partition by tv_id, show_id)))**
then 1
else 0
end as winner_flag
from subQ0
)
What I have:
tv_id show_id partition_count
1 42 1
1 42 2
1 42 3
1 7 1
2 12 1
2 12 2
2 12 3
2 27 1
What I want:
tv_id show_id partition_count flag
1 42 1 1
1 42 2 1
1 42 3 1
1 7 1 0
2 12 1 1
2 12 2 1
2 12 3 1
2 27 1 0
Because tv_id 1 has the most connections to show_id 42, those rows get flagged.
Ideally, something similar to SQL select only rows with max value on a column, but the partitions and grouping have led to issues. This dataset also has billions of rows so a union would be a nightmare.
Thanks in advance!
For each tv_id, you seem to want the show_id that appears the most. If so:
select s.*,
(case when cnt = max(cnt) over (partition by tv_id)
then 1 else 0
end) as flag
from (select s.*, count(*) over (partition by tv_id, show_id) as cnt
from subQ0 s
) s;

SQL Query to fetch employee Attendence

I need to write query on employee table to fetch the employee with employee ID & how many days he is present absent & half-day for given date range.
Employee
AID EmpID Status Date
1 10 Present 17-03-2015
2 10 Absent 18-03-2015
3 10 HalfDay 19-03-2015
4 10 Present 20-03-2015
5 11 Present 21-03-2015
6 11 Absent 22-03-2015
7 11 HalfDay 23-03-2015
Expected Output will be :
EmpID Present Absent HalfDay
10 2 1 1
11 1 1 1
Can you please help me with the Sql query ?
Here Is the query I tried
SELECT EMP.EMPID,
(CASE WHEN EMP.STATUS = 'Present' THEN COUNT(STATUS) ELSE 0 END) Pres,
(CASE WHEN EMP.STATUS = 'Absent' THEN COUNT(STATUS) ELSE 0 END) ABSENT,
(CASE WHEN emp.status = 'HalfDay' THEN Count(status) ELSE 0 END) HalfDay
FROM EMPLOYEE EMP GROUP BY emp.empid
The COUNT() function tests if the value is NOT NULL. Therefore it will always increment for both sides of a CASE statement like this:
COUNT(CASE Status WHEN 'Present' THEN 1 ELSE 0) AS Present
So we need to use SUM() ...
select empid,
sum(case when status='Present' then 1 else 0 end) present_tot,
sum(case when status='Absent' then 1 else 0 end) absent_tot,
sum(case when status='HalfDay' then 1 else 0 end) halfday_tot
from employee
group by empid
order by empid
/
... or use COUNT() with a NULL else clause. Both produce the same output, perhaps this one is clearer:
SQL> select empid,
2 count(case when status='Present' then 1 end) present_tot,
3 count(case when status='Absent' then 1 end) absent_tot,
4 count(case when status='HalfDay' then 1 end) halfday_tot
5 from employee
6 group by empid
7 order by empid
8 /
EMPID PRESENT_TOT ABSENT_TOT HALFDAY_TOT
---------- ----------- ---------- -----------
10 2 1 1
11 1 1 1
SQL>
Note that we need to use ORDER BY to guarantee the order of the result set. Oracle introduced a hashing optimization for aggregations in 10g which meant GROUP BY rarely returns a predictable sort order.
Replace 0 with null because it would be also come in count and added the where clause for date range, check the example below:
select empID,
count(case when status='Present' then 1 else null end) Present_Days,
count(case when status='Absent' then 1 else null end) Absent_Days,
count(case when status='HalfDay' then 1 else null end) HalfDays
from Employee
where date >= to_date('17mar2015') and date <= to_date('23mar2015')
group by empID

Group by in Subquery

I have a table AssignmentMaster in that I have following columns with data
AssignmentID PaidAmount RefundAmount UserID
1 20 0 1
2 10 5 1
3 30 7 2
4 25 0 3
5 35 15 3
6 10 3 1
7 5 0 3
8 10 0 3
Now I want to find out the TotalNumberofAssignment with respect to userID, i.e. result should be:
UserID TotalAssignment TotalAssignmentofRefundAmount TotalPaidAmount TotalRefundAmount
1 3 2 40 8
2 1 1 30 7
3 4 1 75 15
How I can get above given result in MSSQL.
your any help will help me lot.
SELECT
UserID,
COUNT(AssignmentID) AS TotalAssignment,
SUM(SIGN(RefundAmount)) AS TotalAssignmentofRefundAmount,
SUM(PaidAmount) AS TotalPaidAmount,
SUM(RefundAmount) AS TotalRefundAmount
FROM
MyTable
GROUP BY
UserID
Note:
SIGN(RefundAmount) works if RefundAmount is always >= 0.
If not, change to
SUM(CASE WHEN RefundAmount <> 0 THEN 1 ELSE 0 END) AS TotalAssignmentofRefundAmount
Select UserID,
count(1) as TotalAssignment,
sum( case when RefundAmount = 0 then 0 else 1 end) as TotalAssignmentofRefundAmount,
sum(PaidAmount) as TotalPaidAmount ,
sum(RefundAmount) as TotalRefundAmount
From AssignmentMaster
Group by UserID
To show how to do this using nested SQL:
Select UserTotals.UserID, UserTotals.TotalAssignment,
Refunds.TotalAssignmentofRefundAmount,
UserTotals.TotalPaidAmount, UserTotals.TotalRefundAmount
From (select UserID,
Count(AssignmentID) [TotalAssignment],
Sum(PaidAmount) [TotalPaidAmount],
sum(RefundAmount) [TotalRefundAmount]
From #AssignmentMaster
Group By UserID
) [UserTotals] Left Join
(Select UserID,
Count(AssignmentID) [TotalAssignmentofRefundAmount]
From #AssignmentMaster
Where RefundAmount > 0
Group By UserID
) [Refunds] On Refunds.UserID = UserTotals.UserID
select UserId, count (AssignmentID) as TotalAssignment,
sum(case when RefundAmount = 0 then 0 else 1 end) as TotalAssignmentofRefundAmount,
sum(PaidAmount) as TotalPaidAmound,
sum(RefundAmount) as TotalRefundAmount
from AssignmentMaster
group by UserID;