Include zero counts for grouping date ranged based SQL query - sql

I'm trying to group and order the number of sales made in each day from a single 'sales' table with a created_at column and an id column. Each of the records might be created through out the day at any time. I've managed to do this with the following query:
SELECT date_trunc('day', created_at::date) AS period, COUNT(id)
FROM sales
GROUP BY period
ORDER BY period
However, the days with 0 sales are not shown up. Any ideas?
Most of the answers I've found use LEFT JOIN but I can't seem to get it to work, so I might seem to be misunderstanding how to use it. :(
Thank you in advance!

Create a temporary table that returns the required dates and then join to it
DECLARE #StartDateTime DATETIME
DECLARE #EndDateTime DATETIME
SET #StartDateTime = '2015-01-01'
SET #EndDateTime = '2015-01-12';
WITH DateRange(DateData) AS
(
SELECT #StartDateTime as Date
UNION ALL
SELECT DATEADD(d,1,DateData)
FROM DateRange
WHERE DateData < #EndDateTime
)
SELECT DateRange.DateData, Count(sales.id)
FROM sales
right join DateRange on sales.date = DateRange.DateData
group by DateRange.DateData
OPTION (MAXRECURSION 0)

Related

Calculating daily average transaction balance of IDs

need to calculate daily average balance of ids. firstdate is when the ID was generated, currentdate is the dates with balance shown for the IDs.
I am expecting something like this [image 2](manually calculated) for each IDs. So basically need to calculate numbers of days between the firstdate when the id was generated and the last currentdate and the balance should be filled in the blank (between dates) to accurately calculating the daily average.
I created the calender table but not sure how I can get the balance for everyday in order to calculate the average.
CREATE TABLE #Calendar
(
[CalendarDate] DATE
)
DECLARE #StartDate DATE
DECLARE #EndDate DATE
SET #StartDate = '20000101'
SET #EndDate = GETDATE()
WHILE #StartDate <= #EndDate
BEGIN
INSERT INTO #Calendar
(
CalendarDate
)
SELECT
#StartDate
SET #StartDate = DATEADD(day, 1, #StartDate)
Thanks for any help.
Assuming the last observation is weighted to getdate()
There is no need for a calendar table, you can use the window function lead() over() to determine the number of days.
Example
Select ID
,ADB = sum(Balance*Days)/sum(Days)
From (
Select *
,Days = datediff(Day,CurrentDate,lead(CurrentDate,1,getdate() ) over (partition by ID order by CurrentDate ) )
from YourTable
) A
Group By ID
Results
ID ADB
110 109.5597
EDIT
I should add that the window functions can invaluable. They are well worth your time getting comfortable with them.

Stretch the table of balances, for all dates of the calendar

I have a table of stock balances, as of the date of their change
SQLFiddle
I need to stretch these Remains to missing dates including 0 leftovers
I created a calendar
CREATE TABLE Calendar
("Date" DATE)
GO
DECLARE #start datetime
DECLARE #end datetime
SET #start = (SELECT MIN (a.Date) FROM Remains a)
SET #end = GETDATE();
WITH cte AS
(
SELECT #start "Date"
UNION all
SELECT "Date" + 1
FROM cte
WHERE "Date" < #end
)
INSERT INTO Calendar
SELECT cast("Date" AS date) AS "Date"
FROM cte
WHERE "Date" < GETDATE()
option(MAXRECURSION 0)
Where I take the minimum date from the Remains table and drag it until today
Calendar
Next, I join the Calendar to the table of Remains using OUTER APPLY,
SELECT
b.Date
,x.W_Code
,x.Prod_Code
,x.Quality
,x.Count
FROM Calendar b
OUTER APPLY (
SELECT
a.Date
,a.W_Code
,a.Prod_Code
,a.Quality
,a.Count
FROM Remains a
WHERE a.Date = b.Date AND a.Prod_Code = N'00005026957' AND a.W_Code = N'000000017' ) x
and if my query applies to 1 specific warehouse, product and quality, then I get the desired result
Result
But if I remove the condition for the warehouse and the product, the table built incorrectly
I need for each group W_Code, Prod_Code, Quality
have each date from the Calendar
Please help me to find a way to implement this
Maybe I don't need a Calendar
I read about recursive CTE but did not understand how to apply it
How to fill the table with values further, I know, the problem is in the correct joining of the table with dates
Thanks

Count # of Saturdays given a date range

I have a datetime field and a net field. The Sat Count field is done by =IIf(DatePart("w",Fields!DespatchDate.Value)=7,1,0)
I want to total the count of the Saturdays given a starting date and end date (typically a month).
I tried =Sum(IIf(DatePart("w",Fields!DespatchDate.Value)=7,1,0) but the total is wrong.
I also want to count Saturdays for rest of the month, e.g there's a missing 3rd Saturday in the picture.
I also want to do a total of the Net for Saturdays.
Can you point me in the direction. I can do it in SQL or in SSRS
Considering that we do not have any Input or desired output provided, I am assuming that You just want to count Saturdays in a given range:
Select COUNT(*), SUM(Net)
FROM table
WHERE Day# = 7 AND Date BETWEEN '2021-02-16' AND '2021-02-23'
Assuming you want to count saturdays even if it is not part of your dataset, what you need to do is pad out all your dates for the given range and then join it to your base data set.
This would ensure that it accounts for ALL days of the week regardless of a dispatch event occuring on that date / day.
Below is some SQL code that might help you make a start.
declare #startdate date = '2021-02-01'
declare #enddate date = '2021-02-28'
if OBJECT_ID ('tempdb..#dates') is not null
drop table #dates
;WITH mycte AS
(
SELECT CAST(#startdate AS DATETIME) DateValue
UNION ALL
SELECT DateValue + 1
FROM mycte
WHERE DateValue + 1 < #enddate
)
SELECT DateValue into #dates
FROM mycte
OPTION (MAXRECURSION 0)
select
d.DateValue
, datepart(weekday,d.DateValue) as day_no
,case when datepart(weekday,d.DateValue) = 7 then isnull(t.net,0) else 0 end as sat_net
,case when datepart(weekday,d.DateValue) = 1 then isnull(t.net,0) else 0 end as sun_net
from #dates d
left join your_table t
on d.DateValue = t.some_date
drop table #dates
Since I don't know what your required output is, I cannot summarise this any further. But you get the idea!

column values are not showing up

Why can't I get values 0 in the column when #processdate date = null or a Sunday (the transactions are not occurring on Sundays)
This was my original query that only gives me values in the table when #processdate is declared as any day of the week that is not Sunday or null
I need It to show me a 0 in the table when #processdate= null or any sunday
alter procedure USP_CTG_VolumeReport
#processdate date = '1/8/2017'
as
declare #date date = coalesce(#processdate, cast( getdate() as date))
select 'apa' as Source,
cast(AccountID_AssignDT as date)as 'Date',
count(*) as Total_Count
from apa_2000
where
cast(AccountID_AssignDT as date) = #date
group by
cast(AccountID_AssignDT as date)
I should be able to get the proper table with a subquery but for some reason --it is not working
Below is my subquery that is giving me the same result as my previous query
select
'apa' as Source,
cast(AccountID_AssignDT as date)as 'Date',
isnull((select count(*)
from apa_2000
where cast(AccountID_AssignDT as date) = #date)
, 0 ) as Total_Count
from apa_2000
where
cast(AccountID_AssignDT as date) = #date
group by
cast(AccountID_AssignDT as date)
The issue here is that those dates where no processing happens, so the counts would be zero, simply don't exist in the database. You are expecting the query to generate data which isn't there. What you need is a table which includes a list of all the dates you want to report against, and then to match the counts against those dates.
If you are always passing in a single date, the following would work, since the input date is the only date you need:
declare #date as date = '20170416'
select
'apa' as Source,
#date as 'Date',
count(apa_2000.AccountID_AssignDT) as Total_Count
from
(select 1 as x)x
LEFT OUTER JOIN
apa_2000 ON cast(AccountID_AssignDT as date) = #date

SQL query count by week with criteria

I have to write a trend report for the amount of standing scaffolds in the database by week.
I can get a count of scaffolds erected by week in the example below and also dismantles using the same query but this isn't what I need.
SELECT COUNT(scaffID) Erected, WeekStart
FROM
(
SELECT ScaffID,
dateadd(week, datediff(day,0,Erected) / 7, 0) AS WeekStart
FROM Scaffolds
) o
GROUP BY WeekStart
I can get my standing scaffolds from this by putting in a date but I want the standing scaffolds on every Friday say.
Declare #staticDate As DateTime
Set #staticDate = '2/1/2015'
Select COUNT(scaffID) As StandingScaffolds
from RequestInfo
Where ( ErectDate<= #staticDate )
And ( DismantleDate>= #staticDate
or DismantleDate Is NULL
)
This is driving me crazy so any help would be extremely appreciated.
Phil
this should give you something to start with..
DECLARE
#startDate date = '2015-01-01',
#endDate date = '2015-01-28';
with myWeeks (myWeek) AS (
select DATEPART(WEEK,#startDate) myWeek
UNION ALL
select myWeek + 1 from myWeeks
where
myWeek < DATEPART(WEEK,#endDate)
)
select
w,
COUNT(s.Erected) standingScaffolds
from myWeeks w
left join Scaffolds s on
w.myWeek between DATEPART(WEEK,s.Erected) and DATEPART(WEEK,s.Dismantled)
You might want to generate a date table for this (=table with one row for each day). You can then join that with this table to get the calculations quite easily.
select d.date, count(s.scaffID)
from date d, scaffolds s
where s.erected <= d.date and
(dismantled>= d.date or dismantled is NULL) and
d.date >= #stardate and
d.date <= enddate
group by d.date
Hopefully this is ok, can't test right now.
The date table is quite useful in other cases too, for example you can have local holidays there.