Count Number of Saturdays in a date range - SQL - sql-server

I have a report which looks for orders during a given date range... It returns the DateName from the report to give me mondays, it then gives me times from the report, to give me 859 for 08:59 for example.. I then use a case on this report to do the following...
WHEN (DATENAME(DW,T1.DocDate)) = 'Monday' AND T1.DocTime >= '700' AND T1.DocTime <= '859' THEN '1 Monday 07:00-08:59'
What I want to achieve, is the count for "1 Monday 07:00-08:59" to be divided by 2 if there has been 2 mondays, divided by 3 if there has been 3 mondays etc... but I have to be able to have it divide by 3 mondays for example, but 2 wednesdays if the date is a tuesday...
The report currently gives a Total of all orders placed in a datetime grouped together but has no division to average for each day.
SELECT (DATENAME(DW, T1.DocDate)) AS Weekday,
T1.DocTime AS Time,
SUM(T1.DocTotal) AS Value,
CASE
WHEN (DATENAME(DW, T1.DocDate)) = 'Monday'
AND T1.DocTime >= '700'
AND T1.DocTime <= '859' THEN '1 Monday 07:00-08:59'
FROM ORDR T1
INNER JOIN OCRD T0 ON T0.CardCode = T1.CardCode
WHERE (T1.DocDate >= #Start
AND T1.DocDate <= #End)
AND T0.QryGroup20 = 'Y'
AND T1.Canceled = 'N'
GROUP BY T1.DocTime,
T1.DocDate;
I expect the report to count the mondays / tuesdays etc that occur between #START and #END to give me an average sale per day and time.Then be able to then somehow divide by the count of the defined days in the case statement. (I'll hopefully be doing this part in Crystal Reports) but if i can get the first part, I'll work on the second half.

Just cross join the DW_Count subquery, which returns the count of every weekday in your orders range. Then you can count your avg for each weekday
SELECT (DATENAME(DW, T1.DocDate)) AS Weekday,
T1.DocTime AS Time,
SUM(T1.DocTotal) AS Value,
SUM(T1.DocTotal)/(CASE WHEN DATENAME(DW, T1.DocDate) = 'Monday' then DW_Count.MonCount
WHEN DATENAME(DW, T1.DocDate) = 'Tuesday' then DW_Count.TueCount
WHEN DATENAME(DW, T1.DocDate) = 'Wednesday' then DW_Count.WedCount
WHEN DATENAME(DW, T1.DocDate) = 'Thursday' then DW_Count.ThuCount
WHEN DATENAME(DW, T1.DocDate) = 'Friday' then DW_Count.FriCount
WHEN DATENAME(DW, T1.DocDate) = 'Saturday' then DW_Count.SatCount
WHEN DATENAME(DW, T1.DocDate) = 'Sunday' then DW_Count.SunCount) AS AvgValue
CASE
WHEN (DATENAME(DW, T1.DocDate)) = 'Monday'
AND T1.DocTime >= '700'
AND T1.DocTime <= '859' THEN '1 Monday 07:00-08:59'
FROM ORDR T1
INNER JOIN OCRD T0 ON T0.CardCode = T1.CardCode
CROSS JOIN (select sum(case when DATENAME(DW, DW_Count.DateValue) = 'Monday' then 1 else 0 end) as MonCount,
sum(case when DATENAME(DW, DW_Count.DateValue) = 'Tuesday' then 1 else 0 end) as TueCount,
sum(case when DATENAME(DW, DW_Count.DateValue) = 'Wednesday' then 1 else 0 end) as WedCount,
sum(case when DATENAME(DW, DW_Count.DateValue) = 'Thursday' then 1 else 0 end) as ThuCount,
sum(case when DATENAME(DW, DW_Count.DateValue) = 'Friday' then 1 else 0 end) as FriCount,
sum(case when DATENAME(DW, DW_Count.DateValue) = 'Saturday' then 1 else 0 end) as SatCount,
sum(case when DATENAME(DW, DW_Count.DateValue) = 'Sunday' then 1 else 0 end) as SunCount
from (select distinct DocDate from ORDR where (T1.DocDate >= #Start AND T1.DocDate <= #End))) AS DW_Count
WHERE (T1.DocDate >= #Start
AND T1.DocDate <= #End)
AND T0.QryGroup20 = 'Y'
AND T1.Canceled = 'N'
GROUP BY T1.DocTime,
T1.DocDate;

You can use the below logic-
For MSSQL
DECLARE #DT1 DATE = '20190802'
DECLARE #DT2 DATE = '20190820'
DECLARE #SatCount INT = 0
WHILE #DT1<= #DT2
BEGIN
SET #SatCount = #SatCount + CASE WHEN DATEPART(WeekDay,#DT1) = 7 THEN 1 ELSE 0 END
SET #DT1 = DATEADD(DD,1,#DT1)
END
SELECT #SatCount
Just one more option-
DECLARE #DT1 DATE = '20190802',
#DT2 DATE = '20190920';
SELECT SUM(CASE WHEN DATEPART(WeekDay,Date) = 7 THEN 1 ELSE 0 END)
FROM
(
SELECT TOP (DATEDIFF(DAY, #DT1, #DT2) + 1)
Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #DT1)
FROM sys.all_objects a
-- A System table just used for creating multiple rows.
CROSS JOIN sys.all_objects b
-- CROSS JOIN will create number of row = original number of row X original number of row.
)A

Related

previous day's count except on Monday, use Friday's counts

I have the below code. I am comparing counts from today's date to yesterday's date unless date falls on Monday then I want to use Friday's count.
select
cast(getdate() as date)run_dt,
'dx' as db,
'dbo' as [schema],
'tb_cust' as [table],
'completed status' as check_type,
a.curr_cnt,
a.prev_cnt,
abs(cast((a.prev_cnt - a.curr_cnt) / cast(a.curr_cnt as decimal(10,2)) as decimal(5,2))*100) as cal_prcnt_dff,
case
when abs(cast((a.prev_cnt - a.curr_cnt) / cast(a.curr_cnt as decimal(10,2)) * 100 as int) ) >= 100
then 'Y'
else 'N'
end email_trigger,
concat('count on',' ', #curr_dt,' ','[',datename(dw,#curr_dt),']',' ' ,'increased/decreased by 100% from',' ',#prev_dt,' ','[',datename(dw,#prev_dt),']') as 'comment'
from (select
sum(
case
when a.custstatus = 'completed'
and a.custdate = cast(getdate() -1 as date)
then 1
else 0
end) curr_cnt,
sum(
case
when a.custstatus = 'completed'
and a.custtdate = cast(getdate() -2 as date)
--and cast(getdate() as date) in ()
--and datepart(dw,getdate()) in (3,4,5,6)
--or
then 1
else 0
end) prev_cnt,
a.custstatus
from cte_apt a
where 1=1
and a.custstatus = 'completed'
group by
a.custstatus)a
How can I get prev_cnt to count Friday when the day lands on a Monday?
sum(
case
when a.custstatus = 'completed'
and a.custtdate = cast(getdate() -2 as date)
--and cast(getdate() as date) in ()
--and datepart(dw,getdate()) in (3,4,5,6)
--or
then 1
else 0
end) prev_cnt,

How to identify why rows are duplicating

The below query selects all the rows from a master table (there are no duplicates in the table i have checked) and this query counts the number of business days and checks it against a certain number of days, if the count is greater than that certain number of days, it is late, else it is not late. For some reason when I run this query, even with the select DISTINCT, my rows are duplicating. I see a row for each tracking number showing one as Late and the other as Not Late but I don't see how they could possibly be showing both answers? Could anyone help me understand why my rows are being duplicated?
SELECT DISTINCT case UT.[Service] when '0PW' then 'UPS SurePost 1 lb or Greater' else UT.[Service] end as 'Service'
,US.[Region]
,UT.[Tracking_Number] as 'TrackingCounts'
,UT.Manifest_Date
,UT.Date_Delivered
,Ship_To_Postal_Code
,WarehouseLocation
,CASE
WHEN UT.[Service] = 'UPS Ground' AND WarehouseLocation = 'Wausau' then iif(((
DATEDIFF(dd, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END) )
-(DATEDIFF(wk, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END) * 2)
-(CASE WHEN DATENAME(dw, UT.[Manifest_Date]) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, UT.[Date_Delivered]) = 'Saturday' THEN 1 ELSE 0 END)
-(Select Count(*) from [Reporting_Operations].[CORP\u694172].[tbl_HolidayDates] where [HolidayDate] between UT.[Manifest_Date] and UT.[Date_Delivered])) > UZ.TNTDAYS, 1, 0)
WHEN UT.[Service] in ('UPS SurePost 1 lb or Greater','UPS SurePost Less than 1 lb','0PW') AND WarehouseLocation = 'Wausau' then iif(((
DATEDIFF(dd, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END) )
-(DATEDIFF(wk, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END) * 2)
-(CASE WHEN DATENAME(dw, UT.[Manifest_Date]) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, UT.[Date_Delivered]) = 'Saturday' THEN 1 ELSE 0 END)
-(Select Count(*) from [Reporting_Operations].[CORP\u694172].[tbl_HolidayDates] where [HolidayDate] between UT.[Manifest_Date] and UT.[Date_Delivered])) > (UZ.TNTDAYS + 1), 1, 0)
ELSE iif(((
DATEDIFF(dd, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END))
-(DATEDIFF(wk, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END) * 2)
-(CASE WHEN DATENAME(dw, UT.[Manifest_Date]) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, UT.[Date_Delivered]) = 'Saturday' THEN 1 ELSE 0 END)
-(Select Count(*) from [Reporting_Operations].[CORP\u694172].[tbl_HolidayDates] where [HolidayDate] between UT.[Manifest_Date] and UT.[Date_Delivered])) > USS.[Days], 1, 0)
End as LATE
FROM [Reporting_Operations].[CORP\u694172].[tbl_UPS_Automation_QVM_Tracking] UT
INNER JOIN [Reporting_Operations].[CORP\u694172].[tbl_UPS_Automation_States] US on US.[State] = UT.[Ship_To_State_Province]
INNER JOIN [Reporting_Operations].[CORP\u694172].[tbl_UPS_Automation_Ground_Zips] UZ on UZ.[DESTZIPCODE] = UT.[Ship_To_Postal_Code]
INNER JOIN [Reporting_Operations].[CORP\u694172].[tbl_UPS_Automation_Services] USS on UT.[Service] = UT.[Service]
where cast(UT.Manifest_Date as date) between '1/20/2019' and '1/26/2019' AND WarehouseLocation = 'Wausau' and UT.Status = 'Delivered'
group by UT.[Service],US.[Region], USS.Days, UT.[Manifest_Date], UT.[Date_Delivered], TNTDAYS, Tracking_Number, Ship_To_Postal_Code, WarehouseLocation
So I found the issue is on INNER JOIN [Reporting_Operations].[CORP\u694172].[tbl_UPS_Automation_Services] USS on UT.[Service] = UT.[Service]
however I don't understand why when i join UT.SERVICE on USS.Service the uss.service field shows every possible service, and not the value that Ut.SERVICE has.
if UT.Service = UPS 2nd Day Air wouldn't the join on USS only give me UPS 2nd Day Air values?
The root cause is one of the joins returns more than 1 records
The way you need to find the the root cause of issue is:
1- Remove all columns from your select to become Select * from yourtable
2- comment all joins
3- uncomment joins and watch your data to see if the become duplicate
3.1- if the records are not duplicated that join is OK, do the same on next join
3.2- if records get duplicated, means join might not be right, usually some join conditions are missing
4- After fixing the join issue, remove * and bring back the fields
5- do final check

SQL - Add dates and exclude weekends

I've read nearly every question and I must be overlooking something simple, but I cannot get this to calculate correctly for all scenarios. I have a date, and a reference table of different integers that I need to add to specific dates on each row. So for the sake of this question, I've just defined them specifically instead of a more complicated query.
For Date A, I need to add 7 days to the date, but exclude weekends.
For Date B, I need to add 5 days, but same as above, exclude weekends.
I've referenced the code from here,
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2008/10/01'
SET #EndDate = '2008/10/31'
SELECT
(DATEDIFF(dd, #StartDate, #EndDate) + 1)
-(DATEDIFF(wk, #StartDate, #EndDate) * 2)
-(CASE WHEN DATENAME(dw, #StartDate) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, #EndDate) = 'Saturday' THEN 1 ELSE 0 END)
And applied it using my own logic to get this
SELECT '11/05/2015' AS [A Begin]
, 7 AS [A Add]
, CAST(DATEADD(day, ((DATEDIFF(wk, '11/05/2015', DATEADD(day, 7, '11/05/2015')) * 2)
+ (CASE WHEN DATENAME(dw, '11/05/2015') = 'Sunday' THEN 1 ELSE 0 END)
+ (CASE WHEN DATENAME(dw, DATEADD(day, 7, '11/05/2015')) = 'Saturday' THEN 2 ELSE 0 END) + 7), '11/05/2015') AS DATETIME)
+ CAST('16:00' AS DATETIME) AS [A End]
, '11/05/2015' AS [B Begin]
, 5 AS [B Add]
, CAST(DATEADD(day, ((DATEDIFF(wk, '11/05/2015', DATEADD(day, 5, '11/05/2015')) * 2)
+ (CASE WHEN DATENAME(dw, '11/05/2015') = 'Sunday' THEN 1 ELSE 0 END)
+ (CASE WHEN DATENAME(dw, DATEADD(day, 5, '11/05/2015')) = 'Saturday' THEN 2 ELSE 0 END) + 5), '11/05/2015') AS DATETIME)
+ CAST('16:00' AS DATETIME) AS [B End]
For Range A, its adding 7 days, but lands on a Saturday as the End.. which I cannot have, it needs to equal 11/16/2015 to be correct. Range B works just fine. I am not able to perform Declares or any other functions.

SQL - Group Results on Same Row

So I've got data like so
id type date
1 1 2015-02-04
2 1 2015-02-04
3 2 2015-02-04
4 1 2015-02-05
5 2 2015-02-06
And I want a result like so
countForType1 countForType2 dow
2 1 Wednesday
1 0 Thursday
0 1 Friday
etc...
I'm trying use the OVER(PARTITION but I think I'm using it incorrectly, or possibly, I need to use something else. Here is my current query:
SELECT
COUNT(seatType) OVER(PARTITION BY seatType) AS Counts,
CASE DATEPART(DW,testDate)
WHEN 1 THEN 'Sunday'
WHEN 2 THEN 'Monday'
WHEN 3 THEN 'Tuesday'
WHEN 4 THEN 'Wednesday'
WHEN 5 THEN 'Thursday'
WHEN 6 THEN 'Friday'
WHEN 7 THEN 'Saturday'
END dow
FROM tst_Tests
WHERE roomid = 1
GROUP BY DATEPART(DW,testDate), seatType
I'm not sure how to create a second column counting by an individual seat types.
I'm thinking I could just put two select statements inside the select statement, but that seems inefficient. I feel like there is a function for this I am using incorrectly or not at all.
EDIT: I made the example data match actual dates and numbers of what would be returned.
You should use Conditional Aggergate instead of window function
SELECT Count(CASE WHEN type = 1 THEN 1 END) AS countForType1,
Count(CASE WHEN type = 2 THEN 1 END) AS countForType2,
CASE
WHEN Datepart(DW, date) = 1 THEN 'Sunday'
WHEN Datepart(DW, date) = 2 THEN 'Monday'
WHEN Datepart(DW, date) = 3 THEN 'Tuesday'
WHEN Datepart(DW, date) = 4 THEN 'Wednesday'
WHEN Datepart(DW, date) = 5 THEN 'Thursday'
WHEN Datepart(DW, date) = 6 THEN 'Friday'
WHEN Datepart(DW, date) = 7 THEN 'Saturday'
END dow
FROM Yoursampletable
GROUP BY Datepart(DW, date)
Like this?
DECLARE #Example TABLE ([Id] int, [type] int, [testDate] date)
INSERT INTO #Example ([Id], [type], [testDate])
SELECT 1,1,'2015-02-04' UNION ALL
SELECT 2,1,'2015-02-04' UNION ALL
SELECT 3,2,'2015-02-04' UNION ALL
SELECT 4,1,'2015-02-05' UNION ALL
SELECT 5,2,'2015-02-06'
;with rowsWithDayName as (
select *,
CASE WHEN DATEPART(DW,testDate) = 1 THEN 'Sunday'
WHEN DATEPART(DW,testDate) = 2 THEN 'Monday'
WHEN DATEPART(DW,testDate) = 3 THEN 'Tuesday'
WHEN DATEPART(DW,testDate) = 4 THEN 'Wednesday'
WHEN DATEPART(DW,testDate) = 5 THEN 'Thursday'
WHEN DATEPART(DW,testDate) = 6 THEN 'Friday'
WHEN DATEPART(DW,testDate) = 7 THEN 'Saturday'
END as [DayName]
from #Example
)
select
SUM(CASE WHEN [type]=1 THEN 1 ELSE 0 END) as countForType1
, SUM(CASE WHEN [type]=2 THEN 1 ELSE 0 END) as countForType2
, [DayName]
FROM rowsWithDayName
group by [DayName]

SQL Server: How to return value for each past 6 months

I have a query that returns a score on whether or not 3 of the columns = 1 and then if the ProviderID exists in the 2nd table. I need to be able to return a score for each month for 6 months using column Time_Stamp, not including current month. The below returns the score for last month. How can I include the remaining 5 months and ROW_NUMBER() them?
DECLARE #ProviderID int = '1717';
WITH cte as
(
SELECT TOP 1
a.ProviderID, Time_Stamp,
SUM(CASE WHEN [AdditionalReports] = '1' THEN 5 ELSE 0 END) as AdditionalReports,
SUM(CASE WHEN [UniqueReportRequests] = '1' THEN 15 ELSE 0 END) as UniqueReportsRequests,
SUM(CASE WHEN [SurveyCompleted] = '1' THEN 30 ELSE 0 END) as SurveyCompleted,
MAX(CASE WHEN b.ProviderID IS NULL THEN 0 ELSE 50 END) as SubscriptionExists
FROM
ProviderValueCard a
LEFT JOIN
SubscriptionsTV b ON a.ProviderID = b.ProviderID
WHERE
a.ProviderID = #ProviderID AND GroupID = 2
AND Time_Stamp BETWEEN DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) - 1, 0) AND DATEADD(DAY, -(DAY(GETDATE())), GETDATE())
GROUP BY
Time_Stamp, a.ProviderID, event
ORDER BY
event DESC, Time_Stamp DESC
)
SELECT
ProviderID, Time_Stamp,
(AdditionalReports + UniqueReportsRequests + SurveyCompleted + SubscriptionExists) AS TotalScore
FROM
cte
Here is how to grab the first/last day of previous months:
2 months ago:
DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) - 2, 0) as FirstD2monthsago,
DATEADD(DAY, -DAY(GETDATE()), DATEADD(MONTH, -1, GETDATE())) AS last_day_2_months_ago
3 months ago etc:
DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) - 3, 0) as FirstD3monthsago,
DATEADD(DAY, -DAY(GETDATE()), DATEADD(MONTH, -2, GETDATE())) AS last_day_3_months_ago
Desired output
ProviderID Time_Stamp TotalScore Row_Number
----------- ----------------------- -----------
1717 2014-08-29 12:11:17.610 70 1
1717 2014-07-29 12:11:17.610 95 2
1717 2014-06-29 12:11:17.610 100 3
1717 2014-05-29 12:11:17.610 70 4
1717 2014-04-29 12:11:17.610 70 5
1717 6
DECLARE #ProviderID INT, #Now DATETIME, #Months INT
SELECT #ProviderID = 1717, #Now = GETDATE(), #Months = 5
WITH
date_range_cte AS (
SELECT 1 AS RowNum, DATEADD(mm,-1,#Now) AS StartDate, DATEADD(mm,0,#Now) AS EndDate
UNION ALL
SELECT d.RowNum + 1 AS RowNum, DATEADD(mm,(-d.RowNum - 1),#Now) AS StartDate, DATEADD(mm,-d.RowNum,#Now) AS EndDate
FROM date_range_cte d
WHERE d.RowNum + 1 <= #Months
),
main_cte AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY a.ProviderID, d.RowNum, d.StartDate ORDER BY Time_Stamp DESC) AS ordinal_position,
a.ProviderID,
d.RowNum,
d.StartDate,
[AdditionalReports] * 5 AS AdditionalReports,
[UniqueReportRequests] * 15 AS UniqueReportsRequests,
[SurveyCompleted] * 30 as SurveyCompleted,
CASE WHEN b.ProviderID IS NULL THEN 0 ELSE 50 END as SubscriptionExists
FROM ProviderValueCard a
INNER JOIN date_range_cte d ON d.StartDate < Time_Stamp AND Time_Stamp <= d.EndDate
LEFT OUTER JOIN SubscriptionsTV b ON a.ProviderID = b.ProviderID
WHERE a.ProviderID = #ProviderID AND GroupID = 2
)
SELECT ProviderID, RowNum, StartDate, (AdditionalReports + UniqueReportsRequests + SurveyCompleted + SubscriptionExists) AS TotalScore
FROM main_cte
WHERE ordinal_position = 1
ORDER BY RowNum
Here's a couple of ways (psuedocode):
1 - Make a cte just like your existing one for each month you want to get. The only thing you need to change in each one is this line:
AND Time_Stamp BETWEEN DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) - 1, 0) AND DATEADD(DAY, -(DAY(GETDATE())), GETDATE())
For 2 months ago, you would change it to this:
AND Time_Stamp BETWEEN DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) - 2, 0) AND DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) - 1, 0)
and so on for the other months back.
2 - Referring to the same line in your cte above, change it to a -6 to get data for the past 6 months. Then include a MONTH(TimeStamp) column in your select list and group by it to get one row per month for the past 6 months.

Resources