Count for each day return wrong value - sql

The below code gives a count of 1 for each day, and accumulates from today (13/04/2021) til the end of the month and sums them for Saturdays, Sundays and Week days.
;WITH mycte AS (
SELECT GETDATE() DateValue
UNION ALL
SELECT DateValue + 1
FROM mycte
WHERE DateValue < EOMONTH(dateadd(day,-1, getdate()))
)
select
count(case when datepart(dw, DateValue) = 1 then 1 end) SunCount
, count(case when datepart(dw, DateValue) = 7 then 1 end) SatCount
, count(case when datepart(dw, DateValue) between 1 and 7 then 1 end) WeekCount
from mycte
For today (13/04/2021) I would expect the count to be Saturday = 2, Sunday = 2, and Weekdays to be 14 but instead I get 18 til the end of April - why is that?

I think it is because 'between' includes 1 and 7 again, below query should give you remaining 14 week days
;WITH mycte AS (
SELECT GETDATE() DateValue
UNION ALL
SELECT DateValue + 1
FROM mycte
WHERE DateValue < EOMONTH(dateadd(day,-1, getdate()))
)
select
count(case when datepart(dw, DateValue) = 1 then 1 end) SunCount
, count(case when datepart(dw, DateValue) = 7 then 1 end) SatCount
, count(case when datepart(dw, DateValue) between 2 and 6 then 1 end) WeekCount
from mycte

Related

Count of days for rest of month returning incorrect value for EOM date

The below code when run for the last day of the month it is giving me a week day count of 1 when it should be 0 - how can I fix it?
Declare #EndDate DateTime = '03-31-2021'
;WITH mycte AS (
SELECT #EndDate + 1 DateValue
UNION ALL
SELECT DateValue + 1
FROM mycte
WHERE DateValue < EOMONTH(#EndDate)
)
select
count(case when datepart(dw, DateValue) = 1 then 1 end) SunCount
, count(case when datepart(dw, DateValue) = 7 then 1 end) SatCount
, count(case when datepart(dw, DateValue) between 2 and 6 then 1 end) WeekCount
from mycte
Your initial CTE is actually creating a date of 2021-04-01 which is a week day, so that's where your count of 1 is coming from. If you want to restrict the counts to just the month in question, you could add a WHERE clause to your end query like this. This way, you get zeros for all counts.
Declare #EndDate DateTime = '03-31-2021'
;WITH mycte AS (
SELECT #EndDate + 1 DateValue
UNION ALL
SELECT DateValue +1
FROM mycte
WHERE DateValue < EOMONTH(#EndDate)
)
select
count(case when datepart(dw, DateValue) = 1 then 1 end) SunCount
, count(case when datepart(dw, DateValue) = 7 then 1 end) SatCount
, count(case when datepart(dw, DateValue) between 2 and 6 then 1 end) WeekDayCount
from mycte
where DATEPART(MM,DateValue)=DATEPART(MM,#EndDate)

My count CTE returning blanks, how can I get it return as 0?

CTE created to count the number of days left from today's date to end of current month. So my report for today (30 March 2021) did not count tomorrow's date 31 March 2021.
declare #DespatchTo Date = '03-30-2021'
WITH mycte AS
(
SELECT CAST(Convert(date,getdate()) AS DATETIME) DateValue
UNION ALL
SELECT DateValue + 1
FROM mycte
WHERE DateValue < DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, #DespatchTo) + 1, 0)) --03-31-2021
)
SELECT SUN.Count as SunCount, SAT.Count as SatCount, WK.Count as WeekCount
FROM
(SELECT count(*) as Count
FROM mycte
WHERE DatePart("w",DateValue) = 1
group by DatePart("w",DateValue))
As SUN,
(SELECT count(*) as Count
FROM mycte
WHERE DatePart("w",DateValue) = 7
group by DatePart("w",DateValue))
As SAT,
(SELECT distinct SUM(COUNT(*)) OVER() AS Count
FROM mycte
WHERE DatePart("w",DateValue) > 1 AND DatePart("w",DateValue) < 7
group by DatePart("w",DateValue))
As WK
Which returns blank/null results. How can I return as 0?
here is what you need to do:
;WITH mycte AS (
SELECT GETDATE() DateValue
UNION ALL
SELECT DateValue + 1
FROM mycte
WHERE DateValue < EOMONTH(GETDATE())
)
select
count(case when datepart(dw, DateValue) = 1 then 1 end) SUN
, count(case when datepart(dw, DateValue) = 7 then 1 end) SAT
, count(case when datepart(dw, DateValue) between 2 and 6 then 1 end) WK
from mycte
if you want to exclude today, you can adjust cte :
;WITH mycte AS (
SELECT GETDATE() + 1 DateValue
WHERE GETDATE() <> EOMONTH(GETDATE())
UNION ALL
SELECT DateValue + 1
FROM mycte
WHERE DateValue < EOMONTH(GETDATE())
)
select
count(case when datepart(dw, DateValue) = 1 then 1 end) SUN
, count(case when datepart(dw, DateValue) = 7 then 1 end) SAT
, count(case when datepart(dw, DateValue) between 2 and 6 then 1 end) WK
from mycte

SQL- Date Diff- # of week in each month between two date periods

Problem: Display in columns the number of weeks in each month between two date periods (out to three months is fine for now). If possible, from the current day (Dynamic)
Where I currently am:
SELECT Q3.[Begin Date]
,Q3.[End Date]
,Q3.Diff_in_Year
,sum(CASE
WHEN Q3.Year_Counter = 0
THEN datediff(mm, Q3.y_start, Q3.y_end) + 1
ELSE 0
END) Y1
,sum(CASE
WHEN Q3.Year_Counter = 1
THEN datediff(mm, Q3.y_start, Q3.y_end) + 1
ELSE 0
END) Y2
,sum(CASE
WHEN Q3.Year_Counter = 2
THEN datediff(mm, Q3.y_start, Q3.y_end) + 1
ELSE 0
END) Y3
,sum(CASE
WHEN Q3.Year_Counter = 3
THEN datediff(mm, Q3.y_start, Q3.y_end) + 1
ELSE 0
END) Y4
,sum(CASE
WHEN Q3.Year_Counter = 4
THEN datediff(mm, Q3.y_start, Q3.y_end) + 1
ELSE 0
END) Y5
,sum(CASE
WHEN Q3.Year_Counter = 5
THEN datediff(mm, Q3.y_start, Q3.y_end) + 1
ELSE 0
END) Y6
,sum(CASE
WHEN Q3.Year_Counter = 6
THEN datediff(mm, Q3.y_start, Q3.y_end) + 1
ELSE 0
END) Y7
,sum(CASE
WHEN Q3.Year_Counter = 7
THEN datediff(mm, Q3.y_start, Q3.y_end) + 1
ELSE 0
END) Y8
,sum(CASE
WHEN Q3.Year_Counter = 8
THEN datediff(mm, Q3.y_start, Q3.y_end) + 1
ELSE 0
END) Y9
,sum(CASE
WHEN Q3.Year_Counter = 9
THEN datediff(mm, Q3.y_start, Q3.y_end) + 1
ELSE 0
END) Y10
FROM (
SELECT Q1.[Begin Date]
,Q1.[End Date]
,Q1.years Diff_in_Year
,Q2.number AS Year_Counter
,(
CASE
WHEN Q2.number = 0
THEN Q1.[Begin Date]
ELSE dateadd(yy, datediff(yy, 0, dateadd(yy, q2.number, q1.[Begin Date])), 0)
END
) AS y_Start
,(
CASE
WHEN ((Q1.years - 1) = Q2.number)
THEN Q1.[End Date]
ELSE DATEADD(yy, DATEDIFF(yy, 0, dateadd(yy, q2.number + 1, q1.[Begin Date]) + 1), - 1)
END
) AS y_End
,Year(Q1.[Begin Date]) + Q2.number YearInYYYY
FROM (
SELECT [Begin Date]
,[End Date]
,DATEDIFF(year, [Begin Date], [End Date]) + 1 AS years
FROM my dates
) Q1
INNER JOIN master..spt_values Q2 ON Q2.type = 'P'
AND Q2.number < Q1.years
) Q3
GROUP BY Q3.[Begin Date]
,Q3.[End Date]
,q3.Diff_in_Year
How the current code works: Given a date range, the number of months in each year between two dates. IE 1/1/2014 - 1/18/2015 would give two columns "2014" and 2015" the value of 2014 is 12 and the value of 2015 is 1 signifying that there are 13 months between the specified dates.
What I am hoping to achieve is something similar to
Start Date End Date Month 1 Month 2 Month 3
-----------------------------------------------------
1/1/2014 3/8/2014 4 4 1
Dynamic SQL solutions aside (search for dynamic pivot in TSQL), I whipped up a couple of answers. Since your question is unclear whether you want weeks or months, I put together a quick one for each.
Months Example Here:
declare #startdate date = '1/1/2014', #enddate date = '3/1/2015'
select p.*
from (
select #startdate as StartDate, #enddate as EndDate, right(convert(varchar,(dateadd(mm,RowID-1,#startdate)),105),4) [Group]
from (
select *, row_number()over(order by name) as RowID
from master..spt_values
) d
where d.RowID <= datediff(mm, #startdate, #enddate)
) t
pivot (
count([Group]) for [Group] in (
[2014],[2015]
)
) p
Weeks Example Here:
declare #startdate date = '1/1/2014', #enddate date = '3/1/2015'
select p.*
from (
select #startdate as StartDate, #enddate as EndDate, right(convert(varchar,(dateadd(ww,RowID-1,#startdate)),105),7) [Group]
from (
select *, row_number()over(order by name) as RowID
from master..spt_values
) d
where d.RowID <= datediff(ww, #startdate, #enddate)
) t
pivot (
count([Group]) for [Group] in (
[01-2014]
, [02-2014]
, [03-2014]
, [04-2014]
, [05-2014]
, [06-2014]
, [07-2014]
, [08-2014]
, [09-2014]
, [10-2014]
, [11-2014]
, [12-2014]
, [01-2015]
, [02-2015]
, [03-2015]
)
) p

sql timesheet count by day for the week

my table looks like this:
select clocktime, for_UID, in1_out0 from timeclockentries
clocktime for_UID in1_out0
2011-08-07 15:13:58.390 user193 1
2011-08-07 21:09:45.093 user193 0
2011-08-09 14:10:00.000 user193 1
2011-08-09 20:10:00.000 user193 0
I want the results to look like (assuming start of week is Saturday), separated by COLUMNS named 'day1', 'day2', etc.... (but for readability, i've typed them out with linefeeds) :
day1 day2 day3
1900-01-01 00:00:00.000 1900-01-01 05:55:46.700 1900-01-01 00:00:00.000
day4 day5 day6
1900-01-01 06:00:00.000 1900-01-01 00:00:00.000 1900-01-01 00:00:00.000
day7
1900-01-01 00:00:00.000
(i'm using sql2005)
below is what i'm using for a single day:
CREATE PROCEDURE [dbo].[sp_gethoursbyday]
#whichforUID varchar(20),
#whichdate datetime
AS
BEGIN
;WITH CTE as(
SELECT
DENSE_RANK() over (Partition by for_UID , in1_out0 Order by clocktime) id,
clocktime,
for_UID,
in1_out0
FROM
kdhcastle.dbo.timeclockentries tc
WHERE
tc.for_UID = #whichforUID
and month(tc.[clocktime]) = month(#whichdate)
and day(tc.[clocktime]) = day(#whichdate)
and year(tc.[clocktime]) = year(#whichdate)
)
SELECT
Cast(cast(sum(
cast(outTime.clocktime as float) - cast(inTime.clocktime as float)
)as datetime) as datetime) as 'hoursbydy'
FROM
CTE inTime
INNER JOIN CTE outTime
ON inTime.for_UID = outTime.for_UID
AND inTime.id = outTime.id
AND inTime.in1_out0 = 1
and outTime.in1_out0 = 0
END
SELECT
SUM(CASE WHEN DayOfWeek = 1 THEN Duration ELSE 0 END) AS Day1,
SUM(CASE WHEN DayOfWeek = 2 THEN Duration ELSE 0 END) AS Day2,
SUM(CASE WHEN DayOfWeek = 3 THEN Duration ELSE 0 END) AS Day3,
SUM(CASE WHEN DayOfWeek = 4 THEN Duration ELSE 0 END) AS Day4,
SUM(CASE WHEN DayOfWeek = 5 THEN Duration ELSE 0 END) AS Day5,
SUM(CASE WHEN DayOfWeek = 6 THEN Duration ELSE 0 END) AS Day6,
SUM(CASE WHEN DayOfWeek = 7 THEN Duration ELSE 0 END) AS Day7
FROM
(
SELECT
DATEDIFF(DAY, '2011 Jan 01', clocktime) % 7 + 1 AS DayOfWeek,
CAST(MAX(clocktime) - MIN(clocktime) AS FLOAT) AS Duration
FROM
yourTable
GROUP BY
for_UID,
DATEDIFF(DAY, '2011 Jan 01', clocktime)
)
AS [data]
This is more verbose but my focus was (a) to avoid repeating expressions and (b) to simulate all of the input parameters intended to be fed to the stored procedure so that the results are filtered on the desired user / date. Note that the #whichdate parameter is reeled back to the preceding Saturday at midnight, regardless of which day of the week it is or what time is associated with it.
Input parameters:
DECLARE #whichdate DATETIME;
SET #whichdate = '2011-08-08T12:34:00';
DECLARE #whichforUID VARCHAR(32);
SET #whichforUID = 'user193';
Body (just comment out the DECLARE #t / INSERT #t lines, and change #t in the first CTE to the real table name:
SET #whichdate = DATEADD(DAY, -DATEPART(WEEKDAY, #whichdate), #whichdate);
SET #whichdate = DATEADD(DAY, 0, DATEDIFF(DAY, 0, #whichdate));
DECLARE #t TABLE(clocktime DATETIME, for_UID VARCHAR(32), in1_out0 BIT);
INSERT #t SELECT '2011-08-07 15:13:58.390','user193',1
UNION ALL SELECT '2011-08-07 21:09:45.093','user193',0
UNION ALL SELECT '2011-08-09 14:10:00.000','user193',1
UNION ALL SELECT '2011-08-09 20:10:00.000','user193',0;
WITH s(dw, ct, in1_out0) AS
(
SELECT 1 + (DATEDIFF(DAY, '2011-01-01', clocktime) % 7),
clocktime, in1_out0 FROM #t
where for_UID = #whichforUID
AND clocktime >= #whichdate
AND clocktime < DATEADD(DAY, 7, #whichdate)
),
d(dw, min_ct, max_ct) AS
(
SELECT dw,
MIN(CASE WHEN in1_out0 = 1 THEN ct ELSE NULL END),
MAX(CASE WHEN in1_out0 = 0 THEN ct ELSE NULL END)
FROM s GROUP BY dw
),
x AS
(
SELECT d = DATEADD(MILLISECOND, DATEDIFF(MILLISECOND, min_ct, max_ct), 0),
dw FROM d
),
pvt AS (
SELECT * FROM x PIVOT
(MAX(d) FOR dw IN ([1],[2],[3],[4],[5],[6],[7])) AS p
)
SELECT
day1 = COALESCE([1], '19000101'),
day2 = COALESCE([2], '19000101'),
day3 = COALESCE([3], '19000101'),
day4 = COALESCE([4], '19000101'),
day5 = COALESCE([5], '19000101'),
day6 = COALESCE([6], '19000101'),
day7 = COALESCE([7], '19000101')
FROM pvt;

Using a sub query in column list

I would like to create a query that would count how many records were created in the last 7, 14 and 28 days. My result would return something like:
7Days 14Days 28Days
21 35 56
I know how to for each timepsan e.g. 7 days, but I do I capture all three in one query?
select count(*) from Mytable
where Created > DATEADD(day,-8, getdate())
Also not pretty, but doesn't rely on subqueries (table/column names are from AdventureWorks). The case statement returns 1 if it falls within your criteria, 0 otherwise - then you just sum the results :
select sum(case when datediff(day, modifieddate, getdate()) <= 7
then 1 else 0 end) as '7days',
sum(case when datediff(day, modifieddate, getdate()) > 7
and datediff(day, modifieddate, getdate()) <= 14
then 1 else 0 end) as '14days',
sum(case when datediff(day, modifieddate, getdate()) > 14
and datediff(day, modifieddate, getdate()) <= 28
then 1 else 0 end) as '28days'
from sales.salesorderdetail
Edit: Updated the datediff function - the way it was written, it would return a negative number (assuming modifieddate was in the past) causing all items to fall under the first case. Thanks to Andriy M for pointing that out
It isn't the prettiest code in the world, but it does the trick. Try selecting from three subqueries, one for each range.
select * from
(select COUNT(*) as Cnt from Log_UrlRewrites where CreateDate >= DATEADD(day, -7, getdate())) as Seven
inner join (select COUNT(*) as Cnt from Log_UrlRewrites where CreateDate >= DATEADD(day, -14, getdate())) as fourteen on 1 = 1
inner join (select COUNT(*) as Cnt from Log_UrlRewrites where CreateDate >= DATEADD(day, -28, getdate())) as twentyeight on 1 = 1
select
(
select count(*)
from Mytable
where Created > DATEADD(day,-8, getdate())
) as [7Days],
(
select count(*)
from Mytable
where Created > DATEADD(day,-15, getdate())
) as [14Days],
(
select count(*)
from Mytable
where Created > DATEADD(day,-29, getdate())
) as [28Days]
SELECT
[7Days] = COUNT(CASE UtmostRange WHEN 7 THEN 1 END),
[14Days] = COUNT(CASE UtmostRange WHEN 14 THEN 1 END),
[28Days] = COUNT(CASE UtmostRange WHEN 28 THEN 1 END)
FROM (
SELECT
*,
UtmostRange = CASE
WHEN Created > DATEADD(day, -8, GETDATE()) THEN 7
WHEN Created > DATEADD(day, -15, GETDATE()) THEN 14
WHEN Created > DATEADD(day, -29, GETDATE()) THEN 28
END
FROM Mytable
) s