How to display combined result with if statement from multiple rows? - sql

I have below table (screenshot) in database which records approval status as T1_APPROVAL for defects opened on specific date with APP_NAME.
I want to display only 1 row per APP_NAME for specific date.
Eg. if all T1_APPROVAL='Y' where APP_NAME='APP-B' it should display Approved, else Pending.
This is what I roughly prepared so far, but doesn't give the intended result.
SELECT DISTINCT
CASE WHEN t1_approval <> 'Y' THEN 'Pending' ELSE 'Approved' END
AS status
FROM DAV_CR_DEFECT_DPLOYMENT_STATUS
WHERE TRUNC (deploy_date) = TO_DATE ('24-JAN-2018', 'dd-mon-yyyy')
GROUP BY (t1_approval);
If you look at the screenshot, APP-A has one entry as N, and 1 entry as Y -- which should display as PENDING; and for APP-B all T1_APPROVAL is Y -- which should appear as APPROVED.
This is how my end result, should display like:
APP_NAME | T1_APPROVAL
======================
APP-A | PENDING
APP-B | APPROVED

SELECT APP_NAME,
CASE
WHEN AVG(ASCII(T1_APPROVAL)) = ASCII('Y')
THEN 'APPROVED'
ELSE 'PENDING'
END AS T1_APPROVAL
FROM DAV_CR_DEFECT_DPLOYMENT_STATUS
WHERE TRUNC(deploy_date) = TO_DATE('24-JAN-2018', 'dd-mon-yyyy')
GROUP BY APP_NAME
Try that... it's been a long day, and I'm probably forgetting something stupid.
*Edit: forgot to put the date selection clause in.

Take counts of T1_APPROVAL = N for every APP_NAME in an inner query and if it is 0 => PENDING else APPROVED.
SELECT A.DEPLOY_DATE, A.APP_NAME,
CASE WHEN A.PENDING_ENTRIES = 0 THEN 'APPROVED' ELSE 'PENDING' END AS T1_APPROVAL
FROM
(SELECT TRUNC(DEPLOY_DATE) AS DEPLOY_DATE, APP_NAME,
SUM(CASE WHEN T1_APPROVAL = 'N' THEN 1 ELSE 0 END) AS PENDING_ENTRIES
FROM DAV_CR_DEFECT_DPLOYMENT_STATUS
GROUP BY TRUNC(DEPLOY_DATE), APP_NAME) A;

You want a group by and some conditional logic:
SELECT TRUNC(deploy_date), app_name,
(CASE WHEN MIN(TL_APPROVAL) = 'Y' THEN 'Approved' ELSE 'Pending' END) as status
FROM DAV_CR_DEFECT_DPLOYMENT_STATUS
GROUP BY TRUNC(deploy_date), app_name;

You can use MIN too,
SELECT APP_NAME,
DECODE(MIN(T1_APPROVAL), 'Y', 'APPROVED', 'PENDING')
FROM DAV_CR_DEFECT_DPLOYMENT_STATUS
WHERE TRUNC(deploy_date) = TO_DATE('24-JAN-2018', 'dd-mon-yyyy')
GROUP BY APP_NAME

Related

How to exclude 0 from count()? in sql?

I have a code as below where I want to count number of first purchases for a given period of time. I have a column in my sales table where if the buyer is not a first time buyer, then is_first_purchase = 0
For example:
buyer_id = 456391 is already an existing buyer who made purchases on 2 different dates.
Hence is_first_purchase column will show as 0 as per below.
If i do a count() on is_first_purchase for this buyer_id = 456391 then it should return 0 instead of 2.
My query is as follows:
with first_purchases as
(select *,
case when is_first_purchase = 1 then 'Yes' else 'No' end as first_purchase
from sales)
select
count(case when first_purchase = 'Yes' then 1 else 0 end) as no_of_first_purchases
from first_purchases
where buyer_id = 456391
and date_id between '2021-02-01' and '2021-03-01'
order by 1 desc;
It returned the below which is not an intended output
Appreciate if someone can help explain how to exclude is_first_purchase = 0 from the count, thanks.
Because COUNT function count when the value isn't NULL (include 0), if you don't want to count, need to let CASE WHEN return NULL
There are two ways you can count as your expectation, one is SUM other is COUNT but remove the part of else 0
SUM(case when first_purchase = 'Yes' then 1 else 0 end) as no_of_first_purchases
COUNT(case when first_purchase = 'Yes' then 1 end) as no_of_first_purchases
From your question, I would combine CTE and main query as below
select
COUNT(case when is_first_purchase = 1 then 1 end) as no_of_first_purchases
from sales
where buyer_id = 456391
and date_id between '2021-02-01' and '2021-03-01'
order by 1 desc;
I think that you are using COUNT() when you want SUM().
with first_purchases as
(select *,
case when is_first_purchase = 1 then 'Yes' else 'No' end as first_purchase
from sales)
select
SUM(case when first_purchase = 'Yes' then 1 else 0 end) as no_of_first_purchases
from first_purchases
where buyer_id = 456391
and date_id between '2021-02-01' and '2021-03-01'
order by 1 desc;
You could simplify your query as:
SELECT COUNT(*) AS
FROM sales no_of_first_purchases
WHERE is_first_purchase = 1
AND buyer_id = 456391
AND date_id BETWEEN '2021-02-01' AND '2021-03-01'
ORDER BY 1 DESC;
It is better to avoid the use of functions like IF and CASE when it can be done with WHERE.
The simplest approach for Trino (f.k.a. Presto SQL) is to use an aggregate with a filter:
count(name) FILTER (WHERE first_purchase = 'Yes') AS no_of_first_purchases

Query to check if an attribute was in the table from LAST YEAR

Im trying to write a CASE statement to see if school_name with the school_form_status = completed, in the current year has been also completed the previous year.
school_name | School_status | Report date| FORM_PREVIOUS_YEAR
________________________________________________________________________________
Paul Keys | Completed | 03/31/2016 | YES
This is what I have but but not working , im a beginner
select
CASE REPORTED_DATE YEAR = REPORTED_DATE, YEAR,-1,DateAdd(Year,DATEDIFF(YEAR,0,getdate()),0))
THEN 'Y'
ELSE 'N'
END AS FORM_PREV_YEAR,
from
TABLE1
Normally you would JOIN the table against itself:
SELECT this_year.school_name,
this_year.school_status,
this_year.reported_date,
CASE WHEN last_year.school_status = 'Completed' THEN 'Y' ELSE 'N' END AS form_previous_year
FROM table1 AS this_year
LEFT OUTER JOIN table1 AS last_year ON last_year.school_name = this_year.school_name
WHERE this_year.reported_date >= TO_DATE('2017-01-01', 'YYYY-MM-DD')
AND last_year.reported_date BETWEEN TO_DATE('2016-01-01', 'YYYY-MM-DD') AND TO_DATE('2016-12-31', 'YYYY-MM-DD')
AND this_year.school_status = 'Completed'
The statement looks for all schools with the status completed and a reported_date from this year ad then finds the schools with the same name and the reported_date from last year if it exists (LEFT OUTER JOIN). If the last year's status is 'Completed' it will return 'Y' else 'N'.
Try this code:
select
CASE WHEN school_status = 'Completed' and EXTRACT(year from report_date) = EXTRACT(year from sysdate)-1
THEN 'Y'
ELSE 'N'
END AS FORM_PREV_YEAR
from table1;

sql query to get dIvided group

Table - Activity(jobid,duedate,status)
status can be either 'Complete' or "NotComplete".
I need a single sql query to get
how many jobs are complete
how many jobs are not-complete having duedate is greater than current date
how many jobs are not-complete having duedate is less than current date
Can anyone please help me with this? Result should have only 3 rows and two columns.
Edit : I am looking for best query, perhaps with any inbuilt function/keyword which performs task in single line query. Not sure if it is possible.
Something like this:
SELECT Count(jobid) AS total,
'Completed'
FROM activity
GROUP BY status
HAVING status = 'Complete'
UNION
SELECT Count(jobid) AS total,
'Completed Due in past.'
FROM activity
WHERE duedate >= Getdate()
GROUP BY status
HAVING status = 'Complete'
UNION
SELECT Count(jobid) AS total,
'Completed Due in past.'
FROM activity
WHERE duedate < Getdate()
GROUP BY status
HAVING status = 'Complete'
Try case :
select
case when status='Complete' then '1'
when status='NotComplete' and duedate >= getdate() then '2'
else '3' end,
count(jobid)
from Activity
group by
case when status='Complete' then '1'
when status='NotComplete' and duedate >= getdate() then '2'
else '3' end
Try This:-
SELECT COUNT(JOBID) Completed Jobs, STATUS
FROM Activity
WHERE STATUS = "Complete"
GROUP BY STATUS
UNION
SELECT COUNT(JOBID) Completed Jobs, STATUS
FROM Activity
WHERE duedate > GETDATE() AND STATUS = "NotComplete"
GROUP BY STATUS
UNION
SELECT COUNT(JOBID) Completed Jobs, STATUS
FROM Activity
WHERE duedate < GETDATE() AND STATUS = "NotComplete"
GROUP BY STATUS;
This might be helpful to you.
Select sum( case when status = 'Complete' then 1 else 0 end ) as completedJobs,
Sum ( case when status ='NotCompleted' and duedate > getdate() then 1 else 0 end ) as notcompletedinDuedate,
Sum ( case when status ='NotCompleted' and duedate < getdate() then 1 else 0 end ) as notcompletedJobs
From Activity
Everyone, Thanks for your reply. I was looking for best query with 2 columns. This is my solution. If anyone have short/good version query, please suggest.
;with cte as (
select
case
when stat = 'N' and duedate > GETDATE() then 'NG'
when stat = 'N' and duedate < GETDATE() then 'NL'
else stat
end As S, duedate from activity)
select S,COUNT(*) from CTE group by (S)

SQL sum of column value, unique per user per day

I have a postgres table that looks like this:
id | user_id | state | created_at
The state can be any of the following:
new, paying, paid, completing, complete, payment_failed, completion_failed
I need a statement that returns a report with the following:
sum of all paid states by date
sum of all completed states by date
sum of all new, paying, completing states by date with only one per user per day to be counted
sum of all payment_failed, completion_failed by date with only one per user per day to be counted
So far I have this:
SELECT
DATE(created_at) AS date,
SUM(CASE WHEN state = 'complete' THEN 1 ELSE 0 END) AS complete,
SUM(CASE WHEN state = 'paid' THEN 1 ELSE 0 END) AS paid
FROM orders
WHERE created_at BETWEEN ? AND ?
GROUP BY DATE(created_at)
A sum of the in progress and failed states is easy enough by adding this to the select:
SUM(CASE WHEN state IN('new','paying','completing') THEN 1 ELSE 0 END) AS in_progress,
SUM(CASE WHEN state IN('payment_failed','completion_failed') THEN 1 ELSE 0 END) AS failed
But i'm having trouble figuring out how to make only one per user_id per day in_progress and failed states to be counted.
The reason I need this is to manipulate the failure rate in our stats, as many users who trigger a failure or incomplete order go on to trigger more which inflates our failure rate.
Thanking you in advance.
SELECT created_at::date AS the_date
,SUM(CASE WHEN state = 'complete' THEN 1 ELSE 0 END) AS complete
,SUM(CASE WHEN state = 'paid' THEN 1 ELSE 0 END) AS paid
,COUNT(DISTINCT CASE WHEN state IN('new','paying','completing')
THEN user_id ELSE NULL END) AS in_progress
,COUNT(DISTINCT CASE WHEN state IN('payment_failed','completion_failed')
THEN user_id ELSE NULL END) AS failed
FROM orders
WHERE created_at BETWEEN ? AND ?
GROUP BY created_at::date
I use the_date as alias, since it is unwise (while allowed) to use the key word date as identifier.
You could use a similar technique for complete and paid, one is as good as the other there:
COUNT(CASE WHEN state = 'complete' THEN 1 ELSE NULL END) AS complete
Try something like:
SELECT
DATE(created_at) AS date,
SUM(CASE WHEN state = 'complete' THEN 1 ELSE 0 END) AS complete,
SUM(CASE WHEN state = 'paid' THEN 1 ELSE 0 END) AS paid,
COUNT(DISTINCT CASE WHEN state IN('new','paying','completing') THEN user_id ELSE NULL END) AS in_progress,
COUNT(DISTINCT CASE WHEN state IN('payment_failed','completion_failed') THEN user_id ELSE NULL END) AS failed
FROM orders
WHERE created_at BETWEEN ? AND ?
GROUP BY DATE(created_at);
The main idea - COUNT (DISTINCT ...) will count unique user_id and wont count NULL values.
Details: aggregate functions, 4.2.7. Aggregate Expressions
The whole query with same style counts and simplified CASE WHEN ...:
SELECT
DATE(created_at) AS date,
COUNT(CASE WHEN state = 'complete' THEN 1 END) AS complete,
COUNT(CASE WHEN state = 'paid' THEN 1 END) AS paid,
COUNT(DISTINCT CASE WHEN state IN('new','paying','completing') THEN user_id END) AS in_progress,
COUNT(DISTINCT CASE WHEN state IN('payment_failed','completion_failed') THEN user_id END) AS failed
FROM orders
WHERE created_at BETWEEN ? AND ?
GROUP BY DATE(created_at);

Merging data SQL Query

I have a query request where I have to show one customer activity for each web-site but it has to be only one row each, instead of one customer showing multiple times for each activity.
Following is the query I tried but brings lot more rows. please help me as how I can avoid duplicates and show only one customer by each row for each activity.
SELECT i.customer_id, i.SEGMENT AS Pistachio_segment,
(CASE when S.SUBSCRIPTION_TYPE = '5' then 'Y' else 'N' end ) PB_SUBS
(CASE WHEN S.SUBSCRIPTION_TYPE ='12' THEN 'Y' ELSE 'N' END) Daily_test,
(CASE when S.SUBSCRIPTION_TYPE ='8' then 'Y' else 'N' end) COOK_4_2
FROM IDEN_WITH_MAIL_ID i JOIN CUSTOMER_SUBSCRIPTION_FCT S
ON I.IDENTITY_ID = S.IDENTITY_ID and I.CUSTOMER_ID = S.CUSTOMER_ID
WHERE s.site_code ='PB' and s.subscription_end_date is null
Sounds like you need to group by customer_id and perform aggregations for the other columns you are selecting. For example:
sum(case when s.subscription_type = '5' then 1 else 0 end) as pb_subs_count
You could try one of two things:
Use a GROUP BY statement to combine all records with the same id, e.g.,
...
WHERE s.site_code ='PB' and s.subscription_end_date is null
GROUP BY i.customer_id
Use the DISTINCT command in your SELECT, e.g.,
SELECT DISTINCT i.customer_id, i.SEGMENT, ...
you could use a aggregation (SUM) on customer_id, but what do you expect to happen on the other fields? for example, if you have SUBSCRIPTION_TYPE 5 and 13 for the same customer (2 rows), which value do you want?
Perhaps you are looking for something like this:
SELECT i.customer_id, i.SEGMENT AS Pistachio_segment,
MAX(CASE when S.SUBSCRIPTION_TYPE = '5' then 'Y' else 'N' end ) PB_SUBS
MAX(CASE WHEN S.SUBSCRIPTION_TYPE ='12' THEN 'Y' ELSE 'N' END) Daily_test,
MAX(CASE when S.SUBSCRIPTION_TYPE ='8' then 'Y' else 'N' end) COOK_4_2
FROM IDEN_WITH_MAIL_ID i JOIN CUSTOMER_SUBSCRIPTION_FCT S
ON I.IDENTITY_ID = S.IDENTITY_ID and I.CUSTOMER_ID = S.CUSTOMER_ID
WHERE s.site_code ='PB' and s.subscription_end_date is null
GROUP BY i.customer_id, i.SEGMENT
I can't be sure, though, without knowing more about the tables involved.