Select multiple COUNTs for every day - sql

I got a table of Visitors.
Visitor has the following columns:
Id
StartTime (Date)
Purchased (bool)
Shipped (bool)
For each day within the last 7 days, I want to select 3 counts of the Visitors who have that day as StartTime:
The count of total visitors
The count of total visitors where Purchased = true
The count of total visitors where Shipped = true
Ideally the returned result would be:
Day Total TotalPurchased TotalShipped
1 100 67 42
2 82 61 27
etc...
I am used to .NET Linq so this has proved to be quite a challenge for me.
All I have come up with so far is the following:
SELECT COUNT(*) AS Total
FROM [dbo].[Visitors]
WHERE DAY([StartTime]) = DAY(GETDATE())
It selects the total of the current day just fine, however I feel pretty stuck right now so it'd be nice if someone could point me in the right direction.

For the last 7 days use the query proposed by Stanislav but with this WHERE clause
SELECT DAY([StartTime]) theDay,
COUNT(*) AS Tot,
SUM(CASE WHEN Purchased=true THEN 1 ELSE 0 END) as TotPurch,
SUM(CASE WHEN Shipped=true THEN 1 ELSE 0 END) as TotShip
FROM [dbo].[Visitors]
WHERE [StartTime] BETWEEN GETDATE()-7 AND GETDATE()
GROUP BY DAY([StartTime])

SELECT COUNT(*) AS Total,
SUM(CASE WHEN Purchased=true THEN 1 ELSE 0 END) as TotalPurchased,
SUM(CASE WHEN Shipped=true THEN 1 ELSE 0 END) as TotalShipped
FROM [dbo].[Visitors]
WHERE DAY([StartTime]) = DAY(GETDATE())
and add GROUP BY DAY([StartTime]) as jarlh mentioned

Here's a simple select that will give you the dataset you want
SELECT DATEDIFF(day,StartTime, getdate())+1 as [Day], -- Add 1 to display 1 to 7 instead of 0 to 6
COUNT(*) as Total,
SUM(CASE WHEN Purchased = 1 THEN 1 ELSE 0 END) as TotalPurchased,
SUM(CASE WHEN Shipped = 1 THEN 1 ELSE 0 END) AS TotalShipped
FROM Visitors
WHERE DATEDIFF(day,startTime,GETDATE()) < 6
GROUP BY DATEDIFF(day,startTime,GETDATE())
ORDER BY 1
This query will not take into consideration the time component of the date.

Related

Sum all the repeat event based on dates, aggregate by 7 days ,30 days >30 days

I am trying to calculate repeat if there is a repeat event in 3,7,30 and >30 days.
In the image below the the yellow is the sql table,
the green is transformation needed, where I find out what is the first event for Event A and Event B. and then find out what is the gap between the first event of A and next events of A.
Finally I need to aggregate and achieve the blue table where data is aggregate for the unique events.
I have been trying to achieve this in SQL but I am stuck as I am not sure how to filter and loop.
Original data and Expected outcome image
DECLARE #reference_date DATE = '2022-08-02';
SELECT
Event,
MIN(Date) as First_date,
SUM(CASE WHEN DATEDIFF(day, #reference_date, Date) BETWEEN 1 AND 2
THEN 1 ELSE 0 END) as "Within_3_Days",
SUM(CASE WHEN DATEDIFF(day, #reference_date, Date) BETWEEN 1 AND 6
THEN 1 ELSE 0 END) as "Within_7_Days",
SUM(CASE WHEN DATEDIFF(day, #reference_date, Date) BETWEEN 1 AND 29
THEN 1 ELSE 0 END) as "Within_30_Days",
SUM(CASE WHEN DATEDIFF(day, #reference_date, Date)>=30
THEN 1 ELSE 0 END) as ">_30_Days"
FROM event e0
GROUP BY Event
output:
Event
First_date
Within_3_Days
Within_7_Days
Within_30_Days
>_30_Days
A
2022-08-01
0
1
2
1
B
2022-09-15
0
0
0
1
The #reference_date is used to reference the date needed to determine if a date is within x days.
DBFIDDLE
P.S. I use dates in the format YYYY-MM-DD, because that's the only way I am SURE about the ordering of the Day and the Month part.
EDIT:
When using the first date of an event to determine the 'within' columns, you can do:
SELECT
e0.Event,
MIN(e0.Date) as First_date,
SUM(CASE WHEN DATEDIFF(day, e1.Date, e0.Date) BETWEEN 1 AND 2
THEN 1 ELSE 0 END) as "Within_3_Days",
SUM(CASE WHEN DATEDIFF(day, e1.Date, e0.Date) BETWEEN 1 AND 6
THEN 1 ELSE 0 END) as "Within_7_Days",
SUM(CASE WHEN DATEDIFF(day, e1.Date, e0.Date) BETWEEN 1 AND 29
THEN 1 ELSE 0 END) as "Within_30_Days",
SUM(CASE WHEN DATEDIFF(day, e1.Date, e0.Date)>=30
THEN 1 ELSE 0 END) as ">_30_Days"
FROM event e0
INNER JOIN (SELECT Event,MIN(Date) as Date from event GROUP BY Event) e1 on e1.Event=e0.Event
GROUP BY e0.Event
see: DBFIDDLE2

infuse a sum of the value in the another column with a different filter than the total count column

First here's a sample table.
enter image description here
Provider_name patient date status length
AF AGUIR00001 07/05/2018 3 30
AF ABBOT00001 07/05/2018 30
BB ADAMS00001 07/05/2018 3 30
BB ACEVE00001 07/06/2018 3 30
I have created a query that lets me count the total number of appointments versus the number of appointments with a certain status(eg checked out). I was able to create it and group it by provider.
select provider_name,
count(patient) total,
sum(case when status = 3 then 1 else 0 end) as Checkedout
from appointment
group by provider_name
Then I moved on to the next phase which was to get the total length of those appointments with checkedout status. I made this query but it does not break down into each provider.
select provider_name,
count(patient) total,
sum(case when status = 3 then 1 else 0 end) as Checkedout,
(select sum(length) from appointment where status = 3
and date between '06/01/2018' and '07/06/2018')
from appointment where date between '06/01/2018' and '07/06/2018'
group by provider_name
I need it so that the last column in the query is segregated per provider_name.
Thank you in advance for helping me out.
Actually, you were on the right way, try this:
select provider_name,
count(patient) total,
sum(case when status = 3 then 1 else 0 end) as Checkedout,
sum(case when status = 3 then length else 0 end) as len_status3
from appointment
where date between '2018-01-06' and '2018-06-07'
group by provider_name;
According to your last comment, you need a WITH ROLLUP modifier for GROUP BY as in the following :
select coalesce(provider_name,'Total') as provider_name,
count(patient) total,
sum(case when status = 3 then 1 else 0 end) as Checkedout,
sum(case when status = 3 then length else 0 end) as len_status3
from appointment
where date between '2018-01-06' and '2018-06-07'
group by provider_name with rollup;
SQL Fiddle Demo
you shoul do as for checkedoutout
select provider_name,
count(patient) total,
sum(case when status = 3 then 1 else 0 end) as Checkedout,
sum( case when status = 3 then length else 0 ) as total_length
from appointment where date between '06/01/2018' and '07/06/2018'
group by provider_name

Redshift - Aggregate function calls may not have nested aggregate or window function

I am trying to build a SQL query that would count the sum of sales made based on certain values as shown below:
Given below is how my dataset is:
cust_name,sales_count,day_count
cust_a,100,3
cust_a,200,5
cust_a,150,7
cust_a,120,1
cust_a,180,10
cust_a,100,8
cust_b,20,3
cust_b,10,4
cust_b,50,6
cust_b,60,8
cust_b,15,9
I would like to get the output in the below format
cust_name,sales_count,day_count
cust_a,280,last_14
cust_a,450,last_7
cust_b,85,last_14
cust_b,80,last_7
Given below is the case statement I tried to build
select cust_name,
sum(case when day_count > 7 then count(sales_count) else 0 end) as count_14,
sum(case when day_count < 7 then count(sales_count) else 0 end) as count_7
from sales
group by cust_name;
I am using a Amazon Redshift Database.
Found a similar issue in this link (Amazon Redshift - Get week wise sales count by category) but I keep getting aggregate function calls may not have nested aggregate or window function.
Could anyone help trouble shoot this. Thanks.
From your question, you can try this query.
use SUM and CASE WHEN Expression.
select cust_name,
sum(case when day_count > 7 then sales_count else 0 end) as count_14,
sum(case when day_count < 7 then sales_count else 0 end) as count_7
from sales
group by cust_name;
EDIT:
Becasue Aggregate functions can't nest multiple times.
If you want to fix
sum(case when day_count > 7 then count(sales_count) else 0 end)
You can try to write a subquery to fix it.
SELECT cust_name,
sum(case when day_count > 7 then cnt else 0 end) as count_14,
sum(case when day_count < 7 then cnt else 0 end) as count_7
FROM (
SELECT cust_name,(case when day_count > 7 then 1
when day_count < 7 then 2
else null
end) grp,
count(sales_count) cnt
FROM sales
GROUP BY cust_name,
(case when day_count > 7 then 1
when day_count < 7 then 2
else null
end)
)t
WHERE grp is not null
GROUP BY cust_name
to produce the desired output, what you need is just
sum(case when day_count > 7 then sales_count else 0 end)
what you have in the brackets is the expression which output you redirect to the sum function that aggregates it, so for cust_a it produces the following set of values:
cust_a,100,3 -> 0 (3<=7)
cust_a,200,5 -> 0 (5<=7)
cust_a,150,7 -> 0 (7<=7)
cust_a,120,1 -> 0 (1<=7)
cust_a,180,10 -> 180 (10>7)
cust_a,100,8 -> 100 (8>7)
and then the sum is 280

Counts based on hour SQL

How can I get the count per hour?
select count_hr_1, count_hr_2, count_hr_3 from db.table where year=2018 and month=01 and day=02 and hour=01 OR hour=02 OR hour=03;
This SQL/Query is probably invalid but I want to get the counts of hour 1,2,3
If you are able to process the resultset as multiple rows instead of one, you could use GROUP BY:
select hour, count(*)
from db.table
where
year = 2018
and month = 1
and day = 2
and hour in (1, 2, 3)
group by hour
select sum(case when hour = 1 then 1 else 0 end) as count_hr_1,
sum(case when hour = 2 then 1 else 0 end) as count_hr_2,
sum(case when hour = 3 then 1 else 0 end) as count_hr_3
from db.table
where year = 2018
and month = 1
and day = 2
and hour in (1,2,3)

Multiple Count() from a single table

Is there a way to get multiple counts depending on multiple conditions from the same table?
eg. Count for when Days is less than 15, and count for days between 15 and 30.
Yes, you can combine SUM and CASE:
SELECT
SUM(CASE WHEN condition1 THEN 1 ELSE 0 END) count1,
SUM(CASE WHEN condition2 THEN 1 ELSE 0 END) count2
FROM yourtable
So for your specific example:
SELECT
SUM(CASE WHEN days < 15 THEN 1 ELSE 0 END) count1,
SUM(CASE WHEN days BETWEEN 15 AND 30 THEN 1 ELSE 0 END) count2
FROM yourtable
If the majority of rows have days > 30 it might be worth adding a WHERE days <= 30 to the end of the query as an optimization. Also be aware that BETWEEN includes both its end points.