SQL query count by week with criteria - sql

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.

Related

Include zero counts for grouping date ranged based SQL query

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)

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!

SQL Loop Count of people in program during specified duration

I'm not sure if there should be a loop for this or what the easiest approach would be.
My data consists of a list of people participating in our program. They have various start and end dates, but the following equation is able to capture the number of people who participated on a specific date:
DECLARE #PopulationDate DATETIME = '2018-06-01 05:00:00';
select count(People)
FROM Program_Log
WHERE
START_TIME <= #PopulationDate
AND (END_TIME >= #PopulationDate OR END_TIME IS NULL)`
Is there a way I can loop in different date values to get the number of program participants each day for an entire year?
Multiple years?
One simple way is to use a CTE to generate the dates and then a left join to bring in the data. For instance, the following gets the counts as of the first of the month for this year:
with dates as (
select cast('2018-01-01' as date) as dte
union all
select dateadd(month, 1, dte)
from dates
where dte < getdate()
)
select d.dte, count(pl.people)
from dates d left join
program_log pl
on pl.start_time <= d.dte and (pl.end_time >= d.dte or pl.end_time is null)
group by d.dte
order by d.dte;
Note that this will work best for a handful of dates. If you want more than 100, you need to add option (maxrecursion 0) to the end of the query.
Also, count(people) is highly suspicious. Perhaps you mean sum(people) or something similar.

Query to check number of records created in a month.

My table creates a new record with timestamp daily when an integration is successful. I am trying to create a query that would check (preferably automated) the number of days in a month vs number of records in the table within a time frame.
For example, January has 31 days, so i would like to know how many days in january my process was not successful. If the number of records is less than 31, than i know the job failed 31 - x times.
I tried the following but was not getting very far:
SELECT COUNT (DISTINCT CompleteDate)
FROM table
WHERE CompleteDate BETWEEN '01/01/2015' AND '01/31/2015'
Every 7 days the system executes the job twice, so i get two records on the same day, but i am trying to determine the number of days that nothing happened (failures), so i assume some truncation of the date field is needed?!
One way to do this is to use a calendar/date table as the main source of dates in the range and left join with that and count the number of null values.
In absence of a proper date table you can generate a range of dates using a number sequence like the one found in the master..spt_values table:
select count(*) failed
from (
select dateadd(day, number, '2015-01-01') date
from master..spt_values where type='P' and number < 365
) a
left join your_table b on a.date = b.CompleteDate
where b.CompleteDate is null
and a.date BETWEEN '01/01/2015' AND '01/31/2015'
Sample SQL Fiddle (with count grouped by month)
Assuming you have an Integers table*. This query will pull all dates where no record is found in the target table:
declare #StartDate datetime = '01/01/2013',
#EndDate datetime = '12/31/2013'
;with d as (
select *, date = dateadd(d, i - 1 , #StartDate)
from dbo.Integers
where i <= datediff(d, #StartDate, #EndDate) + 1
)
select d.date
from d
where not exists (
select 1 from <target> t
where DATEADD(dd, DATEDIFF(dd, 0, t.<timestamp>), 0) = DATEADD(dd, DATEDIFF(dd, 0, d.date), 0)
)
Between is not safe here
SELECT 31 - count(distinct(convert(date, CompleteDate)))
FROM table
WHERE CompleteDate >= '01/01/2015' AND CompleteDate < '02/01/2015'
You can use the following query:
SELECT DATEDIFF(day, t.d, dateadd(month, 1, t.d)) - COUNT(DISTINCT CompleteDate)
FROM mytable
CROSS APPLY (SELECT CAST(YEAR(CompleteDate) AS VARCHAR(4)) +
RIGHT('0' + CAST(MONTH(CompleteDate) AS VARCHAR(2)), 2) +
'01') t(d)
GROUP BY t.d
SQL Fiddle Demo
Explanation:
The value CROSS APPLY-ied, i.e. t.d, is the ANSI string of the first day of the month of CompleteDate, e.g. '20150101' for 12/01/2015, or 18/01/2015.
DATEDIFF uses the above mentioned value, i.e. t.d, in order to calculate the number of days of the month that CompleteDate belongs to.
GROUP BY essentially groups by (Year, Month), hence COUNT(DISTINCT CompleteDate) returns the number of distinct records per month.
The values returned by the query are the differences of [2] - 1, i.e. the number of failures per month, for each (Year, Month) of your initial data.
If you want to query a specific Year, Month then just simply add a WHERE clause to the above:
WHERE YEAR(CompleteDate) = 2015 AND MONTH(CompleteDate) = 1

MSSQL select count where condition is met across a date range

I have a table containing date, employeeID(int) , and ShiftWorked (can be night/day/weekend or evening) . There is a row for each employee and date combination
I would like to construct a query that gives me a count of how many people have worked a night shift in the week before and after each date in the roster period.
--------------------------------------------------------------------------
Date (yyyy-MM-dd) | CountOfNightshifts(for 1 week either side of date)
--------------------------------------------------------------------------
2012-1-1 | 8
2012-1-2 | 12
2012-1-3 | 11
2012-1-4 | 6
etc | etc
I hope this is clear. I have spent days trying to get this to work but I am not getting anywhere.
For example:
SELECT COUNT(id), [date]
FROM ROSTER
WHERE Shift = night AND [date] BETWEEN DATEADD(D,-7,[date]) AND DATEADD(d,7,[date])
GROUP by [date]
group by [date]
This will give me a list of dates and a count of nights on that particular day - not all night shifts in the 7 days before and after the date.
The following query will return two columns: the reference (roster) date and the number of (distinct) people that have worked on the night sift seven days before to seven days after the reference date.
SELECT tmain.date,
(
SELECT COUNT(DISTINCT taux.employeeId)
FROM roster taux
WHERE taux.shiftWorked = 'night'
AND taux.date >= DATEADD(DAY, -7, tmain.date)
AND taux.date <= DATEADD(DAY, 7, tmain.date)
) AS [number_of_distinct_people_with_night_shift]
FROM roster tmain
ORDER BY tmain.date;
Note 1: Usually I prefer joins over sub-queries, but I guess this solution is easier to read.
Note 2: I am assuming the time component of date values are irrelevant and all dates have the same time (i.e. '00:00:00.00'); if it is not the case, there are more adjustments to be done on the date comparison.
how about this?
SELECT
[date]
,count(*)
FROM
Shifts as s
WHERE
s.Date > DATEADD(day,-7,GETDATE())
AND ShiftWorked = 'Night'
GROUP BY
date
http://sqlfiddle.com/#!3/e88cc/1
a bit more data:
http://sqlfiddle.com/#!3/b7793/2
If you are only interested in a specific date then you could use:
DECLARE #target datetime
SET #target = GETDATE()
SELECT
count(*) as NightShifts
FROM
Shifts as s
WHERE
ShiftWorked = 'Night'
AND s.Date > DATEADD(day,-7,#target)
AND s.Date < DATEADD(day,7,#target)
http://sqlfiddle.com/#!3/b7793/20
but if you have another table that actually has the periods in it (e.g. billing or payroll dates):
DECLARE #target datetime
SET #target = GETDATE()
SELECT
p.periodDate
,count(*)
FROM
Shifts as s
INNER JOIN periods as p
ON s.date > dateadd(day,-7,p.periodDate)
AND s.date < dateadd(day,7,p.periodDate)
WHERE
ShiftWorked = 'Night'
GROUP BY p.periodDate
http://sqlfiddle.com/#!3/fc54d/2
OR to get ) when no night shift was worked:
SELECT
p.periodDate
,ISNULL(t.num,0) as nightShifts
FROM
periods as p
LEFT OUTER JOIN (
SELECT
p.periodDate
,count(*) as num
FROM
Shifts as s
INNER JOIN periods as P
ON s.date > dateadd(day,-7,p.periodDate)
AND s.date < dateadd(day,7,p.periodDate)
WHERE
ShiftWorked = 'Night'
GROUP BY p.periodDate
) as t
ON p.periodDate = t.periodDate
http://sqlfiddle.com/#!3/fc54d/11
You can pull it off by joining the ROSTER table to itself, thereby creating several result rows per employee and day. Otherwise your GROUP BY clause will group the resulting rows from the period you are after into the dates of the original table.
SELECT
r.[date],
COUNT(period.id)
FROM ROSTER r
JOIN ROSTER period
ON period.employeeID=r.employeeID
AND period.shift = night
AND r.[date] BETWEEN DATEADD(d,-7,period.[date]) and DATEADD(d,7,period.[date])
WHERE
r.shift = night
GROUP BY r.[date]