How to use having condition in SQL query - sql

SELECT
userid,
CASE
WHEN (COUNT(CASE
WHEN onlinesportsgamewagers != 0
THEN 1
ELSE null
END)
+ COUNT(CASE
WHEN depositmade_amt != 0
THEN 1
ELSE null
END)) >= 10
THEN "VIP"
ELSE "NON-VIP"
END as VIPcheck
FROM
player_activity
WHERE
userid = 2023410
GROUP BY
year(txndate), month(txndate)
This query determines the user's VIP status for each month.
Ultimately, I want to have a query that determines if the user achieved VIP status for at least 3 months (including the current month). For the time being, it's only user 2023410, but eventually I want to run this for the whole database.
Therefore my ultimate output would be:
User - VIPcheck (3 different months w/ active status)
(one row per userID)
HAVING COUNT(CASE WHEN (COUNT(CASE WHEN onlinesportsgamewagers != 0
THEN 1
ELSE null
END)
+ COUNT(CASE WHEN depositmade_amt != 0
THEN 1
ELSE null
END)) >= 10
THEN 1
ELSE 0
END)
Tried the above having statement, but it didn't work. Any suggestions?

If I understand correctly, this gets the VIP status for one user by month:
SELECT userid, year(txndate), month(txndate),
(CASE WHEN SUM(CASE WHEN onlinesportsgamewagers <> 0 THEN 1 ELSE 0 END) +
SUM(CASE WHEN depositmade_amt <> 0 THEN 1 ELSE 0 END) >= 10
THEN 'VIP'
ELSE 'NON-VIP'
END) as VIPcheck
FROM player_activity
GROUP BY userid, year(txndate), month(txndate);
Another aggregation will get what you want:
SELECT userid,
(CASE WHEN SUM(VIPcheck = 'VIP') >= 3 THEN 'SUPER-VIP'
WHEN SUM(VIPcheck = 'VIP') >= 1 THEN 'VIP'
ELSE 'HOI POLLOI'
END) as status
FROM (SELECT userid, year(txndate), month(txndate),
(CASE WHEN SUM(CASE WHEN onlinesportsgamewagers <> 0 THEN 1 ELSE 0 END) +
SUM(CASE WHEN depositmade_amt <> 0 THEN 1 ELSE 0 END) >= 10
THEN 'VIP'
ELSE 'NON-VIP'
END) as VIPcheck
FROM player_activity
GROUP BY userid, year(txndate), month(txndate)
) uym
GROUP BY userid;

Related

Is there a way to rewrite this statement without sub queries?

I am trying to combine 4 queries for a monthly report so that I don't have to run them seperately. Our internal accounting software appears doesn't support sub queries so this statement doesn't work.
select left(salesgroupcode,4) as "Sales Group",
count(Number_of_products),
count(Number_of_discontinued),
count(Number_not_uploaded),
count(Number_sitting)
from (select
case when quantityavailable > 1 then 1 end Number_of_products,
case when quantityavailable > 1 and discontinued = true then 1 end Number_of_discontinued,
case when quantityavailable > 1 and z_datefirstuploaded is null then 1 end Number_not_uploaded,
case when quantityavailable > 1 and z_datefirstuploaded is null and dateoflastsale <= '01/01/2019' then 1 end Number_sitting
from icprod
) icprod
I don't have any other info about the specific rules etc that the software allows so I'm happy to try anything.
Thanks in advance.
Any help is appreciated
Yes, it is possible:
select left(salesgroupcode,4) as "Sales Group",
count(*),
count(case when discontinued = true then 1 end ),
count(case when z_datefirstuploaded is null then 1 end),
count(case when z_datefirstuploaded is null and dateoflastsale <= '01/01/2019')
from icprod
where quantityavailable > 1
group by left(salesgroupcode,4)
Just use conditional aggregation:
select sum(case when quantityavailable > 1 then 1 else 0 end ) as Number_of_products,
sum(case when quantityavailable > 1 and discontinued = true then 1 else 0 end) as Number_of_discontinued,
sum(case when quantityavailable > 1 and z_datefirstuploaded is null then 1 else 0 end) as Number_not_uploaded,
sum(case when quantityavailable > 1 and z_datefirstuploaded is null and dateoflastsale <= '2019-01-01' then 1 else 0 end) as Number_sitting
from icprod;
Notes that I changed the date constant to be ISO 8601 standard format. In some databases, you may need to precede that with date.
This can in turn be simplified to:
select count(*) as Number_of_products,
sum(case when discontinued = true then 1 else 0 end) as Number_of_discontinued,
sum(case when z_datefirstuploaded is null then 1 else 0 end) as Number_not_uploaded,
sum(case when z_datefirstuploaded is null and dateoflastsale <= '2019-01-01' then 1 else 0 end) as Number_sitting
from icprod
where quantityavailable > 1

How to calculate a Cumulative total using SQL

I have a Tickets table in My database , each Ticket have a status_id (1,2,3)
1: Ticket IN PROGRESS
2: Ticket Out Of time
3: Ticket Closed
I want using SQL to calculate the number of tickets for each status .
Calculate the cumulative total for each Status in a specific Date, I have already a column affectation_Date that contains the date where the status of ticket has been changed .
Use conditional aggregation as
SELECT TicketID,
AffectationDate,
SUM(CASE WHEN StatusID = 1 THEN 1 ELSE 0 END) InProgress,
SUM(CASE WHEN StatusID = 2 THEN 1 ELSE 0 END) OuOfTime,
SUM(CASE WHEN StatusID = 3 THEN 1 ELSE 0 END) Closed,
COUNT(1) Total
FROM Tickets
GROUP BY TicketID,
AffectationDate
ORDER BY TicketID,
AffectationDate;
Or if you want to GROUP BY AffectationDate only
SELECT AffectationDate,
SUM(CASE WHEN StatusID = 1 THEN 1 ELSE 0 END) TotalInProgress,
SUM(CASE WHEN StatusID = 2 THEN 1 ELSE 0 END) TotalOutOfTime,
SUM(CASE WHEN StatusID = 3 THEN 1 ELSE 0 END) TotalClosed,
COUNT(1) TotalStatusThisDate
FROM Tickets
GROUP BY AffectationDate
ORDER BY AffectationDate;
Live Demo
Using conditional counts.
SELECT affectation_Date,
COUNT(CASE WHEN status_id = 1 THEN 1 END) AS TotalInProgress,
COUNT(CASE WHEN status_id = 2 THEN 1 END) AS TotalOutOfTime,
COUNT(CASE WHEN status_id = 3 THEN 1 END) AS TotalClosed
FROM Tickets t
GROUP BY affectation_Date
ORDER BY affectation_Date
you may use the desired filter condition for the date criteria
SELECT COUNT(1), STATUS
FROM tickets
WHERE affectation_Date >= 'someDate'
group by status
Regards
You just need to group by status and count the number of tickets in each group:
select status, count(*) as number
from Tickets
where dt >= '2019-01-01 00:00:00' and dt < '2019-01-02 00:00:00'
group by status
having status >= 1 and status <= 3
This adds the Cumulative Sum to the existing answers:
SELECT AffectationDate,
Sum(CASE WHEN StatusID = 1 THEN 1 ELSE 0 END) AS TotalInProgress,
Sum(CASE WHEN StatusID = 2 THEN 1 ELSE 0 END) AS TotalOutOfTime,
Sum(CASE WHEN StatusID = 3 THEN 1 ELSE 0 END) AS TotalClosed,
Count(*) as TotalStatusThisDate,
Sum(Sum(CASE WHEN StatusID = 1 THEN 1 ELSE 0 END)) Over (ORDER BY AffectationDate) AS cumTotalInProgress,
Sum(Sum(CASE WHEN StatusID = 2 THEN 1 ELSE 0 END)) Over (ORDER BY AffectationDate) AS cumTotalOutOfTime,
Sum(Sum(CASE WHEN StatusID = 3 THEN 1 ELSE 0 END)) Over (ORDER BY AffectationDate) AS cumTotalClosed,
Sum(Count(*)) Over (ORDER BY AffectationDate) AS cumTotalStatusThisDate
FROM Tickets
GROUP BY AffectationDate
ORDER BY AffectationDate;

Exclude records that have sum greater than 1

I have query returning details of customers that are subscribed to channel xyz or all other channels.
To generate this results i am using the following query:
select customerID
,sum(case when channel='xyz' then 1 else 0 end) as 'xyz Count'
,sum(case when channel<>'xyz' then bundle_qty else 0 end) as 'Other'
From temptable
So my Question is, how do i Exclude customers that are subscribed to 2 channels, where one is xyz and one is another channel.
select customerID
,sum(case when channel='xyz' then 1 else 0 end) as 'xyz Count'
,sum(case when channel<>'xyz' then bundle_qty else 0 end) as 'Other'
From temptable
group by customerID
having sum(case when channel= 'xyz' then 1 else 0 end) > 0
and sum(case when channel<>'xyz' then 1 else 0 end) > 0
First, your query is not correct. It needs a group by. Second, you can do what you want using having:
select customerID,
sum(case when channel = 'xyz' then 1 else 0 end) as xyz_Count,
sum(case when channel<>'xyz' then bundle_qty else 0 end) as Other
From temptable
group by customerID
having count(*) = 2 and
sum(case when channel = 'xyz' then 1 else 0 end) = 1;
If customers can subscribe to the same channel multiple times, and you still want only "xyz" and another channel, then:
having count(distinct channel) = 2 and
(min(channel) = 'xyz' or max(channel) = 'xyz')

Full outer join with "case when" and subquery

I have a full outer join query with case when and sub query in oracle. What I am trying to accomplish is aggregating current year data and previous year data from the same table in order to compare them. However my FULL OUTER JOIN is acting as an inner join not returning the null values from both the current year and the previous year.
Here is my code:
SELECT
SQ1.CHANNEL,
SQ1.SHORT,
SQ1.NAME,
SQ1.RDC,
SQ1.CY_APPROVED_COUNT,
SQ2.PY_APPROVED_COUNT,
SQ1.CY_APPROVED_VOLUME,
SQ2.PY_APPROVED_VOLUME,
SQ1.CY_DECLINED_COUNT,
SQ2.PY_DECLINED_COUNT,
SQ1.CY_DECLINED_VOLUME,
SQ2.PY_DECLINED_VOLUME,
SQ1.CY_RETURNED_COUNT,
SQ2.PY_RETURNED_COUNT,
SQ1.CY_RETURNED_VOLUME,
SQ2.PY_RETURNED_VOLUME
FROM ( SELECT
CHANNEL,
SHORT,
NAME,
RDC,
SUM (CASE WHEN STATUS = 'Approved' THEN APP_COUNTS ELSE 0 END) AS CY_APPROVED_COUNT,
SUM (CASE WHEN STATUS = 'Approved' THEN PROJ_VOL ELSE 0 END) AS CY_APPROVED_VOLUME,
SUM (CASE WHEN STATUS = 'Declined' THEN APP_COUNTS ELSE 0 END) AS CY_DECLINED_COUNT,
SUM (CASE WHEN STATUS = 'Declined' THEN PROJ_VOL ELSE 0 END) AS CY_DECLINED_VOLUME,
SUM (CASE WHEN STATUS = 'Returned' THEN APP_COUNTS ELSE 0 END) AS CY_RETURNED_COUNT,
SUM (CASE WHEN STATUS = 'Returned' THEN PROJ_VOL ELSE 0 END) AS CY_RETURNED_VOLUME
FROM WFRT_MSP_SP_MTD
WHERE PERIOD >= TO_DATE('2016/02/01', 'yyyy/mm/dd')
AND PERIOD <= TO_DATE('2016/02/13','yyyy/mm/dd')
AND CHANNEL = 'MSP'
AND RDC = 'BASE'
GROUP BY
CHANNEL,
SHORT,
NAME,
RDC
) SQ1
-- NOT CORRECTLY SHOWING NULL VALUES
FULL OUTER JOIN
( SELECT
CHANNEL,
SHORT,
NAME,
RDC,
SUM (CASE WHEN STATUS = 'Approved' THEN APP_COUNTS ELSE 0 END) AS PY_APPROVED_COUNT,
SUM (CASE WHEN STATUS = 'Approved' THEN PROJ_VOL ELSE 0 END) AS PY_APPROVED_VOLUME,
SUM (CASE WHEN STATUS = 'Declined' THEN APP_COUNTS ELSE 0 END) AS PY_DECLINED_COUNT,
SUM (CASE WHEN STATUS = 'Declined' THEN PROJ_VOL ELSE 0 END) AS PY_DECLINED_VOLUME,
SUM (CASE WHEN STATUS = 'Returned' THEN APP_COUNTS ELSE 0 END) AS PY_RETURNED_COUNT,
SUM (CASE WHEN STATUS = 'Returned' THEN PROJ_VOL ELSE 0 END) AS PY_RETURNED_VOLUME
FROM WFRT_MSP_SP_MTD
WHERE PERIOD >= TO_DATE('2015/02/01', 'yyyy/mm/dd')
AND PERIOD <= TO_DATE('2015/02/13','yyyy/mm/dd')
AND CHANNEL = 'MSP'
AND RDC = 'BASE'
GROUP BY
CHANNEL,
SHORT,
NAME,
RDC
) SQ2
ON sq1.short = sq2.short
;
Please help if you can.
Just use conditional aggregation:
SELECT CHANNEL, SHORT, NAME, RDC,
SUM(CASE WHEN this_year = 1 AND STATUS = 'Approved' THEN APP_COUNTS ELSE 0 END) AS CY_APPROVED_COUNT,
SUM(CASE WHEN this_year = 1 AND STATUS = 'Approved' THEN PROJ_VOL ELSE 0 END) AS cY_APPROVED_VOLUME,
SUM(CASE WHEN this_year = 1 AND STATUS = 'Declined' THEN APP_COUNTS ELSE 0 END) AS CY_DECLINED_COUNT,
SUM(CASE WHEN this_year = 1 AND STATUS = 'Declined' THEN PROJ_VOL ELSE 0 END) AS CY_DECLINED_VOLUME,
SUM(CASE WHEN this_year = 1 AND STATUS = 'Returned' THEN APP_COUNTS ELSE 0 END) AS CY_RETURNED_COUNT,
SUM(CASE WHEN this_year = 1 AND STATUS = 'Returned' THEN PROJ_VOL ELSE 0 END) AS CY_RETURNED_VOLUME,
SUM(CASE WHEN prev_year = 1 AND STATUS = 'Approved' THEN APP_COUNTS ELSE 0 END) AS PY_APPROVED_COUNT,
SUM(CASE WHEN prev_year = 1 AND STATUS = 'Approved' THEN PROJ_VOL ELSE 0 END) AS PY_APPROVED_VOLUME,
SUM(CASE WHEN prev_year = 1 AND STATUS = 'Declined' THEN APP_COUNTS ELSE 0 END) AS PY_DECLINED_COUNT,
SUM(CASE WHEN prev_year = 1 AND STATUS = 'Declined' THEN PROJ_VOL ELSE 0 END) AS PY_DECLINED_VOLUME,
SUM(CASE WHEN prev_year = 1 AND STATUS = 'Returned' THEN APP_COUNTS ELSE 0 END) AS PY_RETURNED_COUNT,
SUM(CASE WHEN prev_year = 1 AND STATUS = 'Returned' THEN PROJ_VOL ELSE 0 END) AS PY_RETURNED_VOLUME
FROM (SELECT msm.*,
(CASE WHEN PERIOD >= DATE '2015-02-01' AND
PERIOD <= '2015-02-13'
THEN 1 ELSE 0
END) as prev_year,
(CASE WHEN PERIOD >= DATE '2016-02-01' AND
PERIOD <= '2016-02-13'
THEN 1 ELSE 0
END) as this_year
FROM WFRT_MSP_SP_MTD msm
) msm
WHERE CHANNEL = 'MSP' AND RDC = 'BASE'
GROUP BY CHANNEL, SHORT, NAME, RDC;

GROUP BY WEEK with SQL

I have the following:
http://sqlfiddle.com/#!6/226ae/1
I'm trying to now add one row for each week of the year, and filter the contacts accordingly. CONTACTS has a datetime column. The new table will look like:
Status 1 Status 2 Status 3
Week 1 3 4 2
Week 2 1 5 3
Week 3 2 2 4
I think that DATEADD needs to be used, however I'm at a loss in terms of how to begin changing my query.
I do know that MySQL has a GROUP BY WEEK command, but I don't think that SQL has an equivalent. What's the best way to accomplish this?
You can use DATEPART(), this groups by both the week and the year in the event you have data spanning multiple years:
SELECT
'Week ' + cast(datepart(wk, created) as varchar(2)) Week,
SUM(case WHEN status = 1 then 1 else 0 end) Status1,
SUM(case WHEN status = 2 then 1 else 0 end) Status2,
SUM(case WHEN status = 3 then 1 else 0 end) Status3,
SUM(case WHEN status = 4 then 1 else 0 end) Status4,
SUM(case WHEN status = 5 then 1 else 0 end) Status5
FROM contacts
group by datepart(wk, created), year(created)
See SQL Fiddle with Demo
Adding the year to the final result:
SELECT
'Week ' + cast(datepart(wk, created) as varchar(2)) Week,
year(created) year,
SUM(case WHEN status = 1 then 1 else 0 end) Status1,
SUM(case WHEN status = 2 then 1 else 0 end) Status2,
SUM(case WHEN status = 3 then 1 else 0 end) Status3,
SUM(case WHEN status = 4 then 1 else 0 end) Status4,
SUM(case WHEN status = 5 then 1 else 0 end) Status5
FROM contacts
group by datepart(wk, created), year(created)
See SQL Fiddle with demo
You can use the datepart function to extract the week from a date.
The query becomes:
SELECT datepart(week, created) as week,
SUM(case WHEN status = 1 then 1 else 0 end) Status1,
SUM(case WHEN status = 2 then 1 else 0 end) Status2,
SUM(case WHEN status = 3 then 1 else 0 end) Status3,
SUM(case WHEN status = 4 then 1 else 0 end) Status4,
SUM(case WHEN status = 5 then 1 else 0 end) Status5
FROM contacts
group by datepart(week, created)
SqlFiddle: http://sqlfiddle.com/#!6/226ae/6tsq
You might try using the group by clause in your query:
SELECT
DATE_FORMAT( created, '%u' ) week_number,
SUM(case WHEN status = 1 then 1 else 0 end) Status1,
SUM(case WHEN status = 2 then 1 else 0 end) Status2,
SUM(case WHEN status = 3 then 1 else 0 end) Status3,
SUM(case WHEN status = 4 then 1 else 0 end) Status4,
SUM(case WHEN status = 5 then 1 else 0 end) Status5
FROM contacts
GROUP BY DATE_FORMAT( created, '%u' )
I'm assuming you are talking about mysql.
The DATE_FORMAT function is documented here:
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-format