column values are not showing up - sql

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

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!

How to store n number of SELECT results into variable?

So, i have this statement that returns OrderDates of all orders made by a customer. I'm trying to store the orderdates into a variable or multiple variable, to calculate average.
I know that for a specific result we can do something like this
DECLARE #tempvar DATE
SET #tempvar = (SELECT OrderDate From Orders WHERE CustID = '1234')
But issue is, what if select statement returns variable number of results (variable rows), like 0 results or 2 results or 4?
I know we can get number of rows returned by a select statement by ##ROWCOUNT variable.
To put my issue in simpler words, i need to store newest and oldest date returned by select statement, and divide it by number of rows returned.
If your main objective is to get the average of the dates, for that you don't need to store the dates to a variable, you can do it directly like following.
SELECT CAST(AVG(CAST(OrderDate AS FLOAT)) AS DATETIME) FROM Orders WHERE CustID = '1234'
You can also store the average of all date inside a variable, you can do it like following.
DECLARE #AvgDate DATETIME
SELECT #AvgDate = CAST(AVG(CAST(OrderDate AS FLOAT)) AS DATETIME)
FROM Orders WHERE CustID = '1234'
Still if you want to store the dates into some variable, in that case to store more than 1 value better choose a table datatype as following.
DECLARE #OrderDates TABLE(OrderDate DATETIME)
INSERT INTO #OrderDates(OrderDate)
SELECT OrderDate From [Orders] WHERE CustID = '1234'
--TO GET AVG
SELECT CAST(AVG(CAST(OrderDate AS FLOAT)) AS DATETIME) FROM #OrderDates ;
-- RETURNS ALL ROW
SELECT * FROM #OrderDates
Edit :
To put my issue in other words, i need to get number of days between
highest and smallest date returned by SELECT statement
To find the days between MAX date and Min Date, you can do like following.
SELECT DATEDIFF(day, MIN(OrderDate), MAX(OrderDate)) FROM #OrderDates
OR
SELECT DATEDIFF(day, MIN(OrderDate), MAX(OrderDate)) FROM Orders WHERE CustID = '1234'
I think this gets you what you want in just one line of code:
select dateadd(d, avg(datediff(d, '1970-01-01', OrderDate)), '19700101') from Orders where CustID = '1234'
In response to comment below, try:
select
dateadd(d, datediff(d, '1970-01-01', max(OrderDate)) - datediff(d, '1970-01-01', min(OrderDate)) / count(*), '1970-01-01') as requested_calc,
dateadd(d, avg(datediff(d, '1970-01-01', OrderDate)), '19700101') as avg_date
from Orders
where CustID = '1234'
But for the life of me, I don't understand why you would want this calc. So I kept the other too.
I hope this helps.

How to count number of work days and hours extracting public holidays between two dates in SQL

I am new to SQL and stuck in some complex query.
What am I trying to achieve?
I want to calculate following two types of total days between two timestamp fields.
Number of Working Days (Excluding Weekend & Public Holidays)
Number of Total Days (Including Weekend & Public Holidays)
Calculation Condition
If OrderDate time is <= 12:00 PM then start count from 0
If OrderDate Time is > 12:00 PM then start count from -1
If Delivery Date is NULL then count different till Today's Date
Data Model
OrderDate & DeliveryDate resides in 'OrderTable'
PublicHolidayDate resides 'PublicHolidaysTable'
As with many tasks in SQL, this could be solved in multiple ways.
You can use COUNT aggregate operations on the date range with the BETWEEN operator to give you aggregate totals of the weekend days and holidays from a start date (OrderDate) to an end date (DeliveryDate).
This functionality can be combined with CTEs (Common Table Expressions) to give you the end result set you are looking for.
I've put together a query that illustrates one way you could go about doing it. I've also put together some test data and results to illustrate how the query works.
DECLARE #DateRangeBegin DATETIME = '2016-01-01'
, #DateRangeEnd DATETIME = '2016-07-01'
DECLARE #OrderTable TABLE
(OrderNum INT, OrderDate DATETIME, DeliveryDate DATETIME)
INSERT INTO #OrderTable VALUES
(1, '2016-02-12 09:30', '2016-03-01 13:00')
, (2, '2016-03-15 13:00', '2016-03-30 13:00')
, (3, '2016-03-22 14:00', NULL)
, (4, '2016-05-06 10:00', '2016-05-19 13:00')
DECLARE #PublicHolidaysTable TABLE
(PublicHolidayDate DATETIME, Description NVARCHAR(255))
INSERT INTO #PublicHolidaysTable VALUES
('2016-02-15', 'President''s Day')
, ('2016-03-17', 'St. Patrick''s Day')
, ('2016-03-25', 'Good Friday')
, ('2016-03-27', 'Easter Sunday')
, ('2016-05-05', 'Cinco de Mayo')
Some considerations you may of already thought of are that you don't want to count both weekend days and holidays that occur on a weekend, unless your company observes the holiday on the next Monday. For simplicity, I've excluded any holiday that occurs on a weekend day in the query.
You'll also want to limit this type of query to a specific date range.
The first CTE (cteAllDates) gets all dates between the start and end date range.
The second CTE (cteWeekendDates) gets all weekend dates from the first CTE (cteAllDates).
The third CTE (ctePublicHolidays) gets all holidays that occur on weekdays from your PublicHolidaysTable.
The last CTE (cteOrders) fulfills the requirement that the count of total days and working days must begin from the next day if the OrderDate is after 12:00PM and the requirement that the DeliveryDate should use today's date if it is null.
The select statement at the end of the CTE statements gets your total day count, weekend count, holiday count, and working days for each order.
;WITH cteAllDates AS (
SELECT 1 [DayID]
, #DateRangeBegin [CalendarDate]
, DATENAME(dw, #DateRangeBegin) [NameOfDay]
UNION ALL
SELECT cteAllDates.DayID + 1 [DayID]
, DATEADD(dd, 1 ,cteAllDates.CalendarDate) [CalenderDate]
, DATENAME(dw, DATEADD(d, 1 ,cteAllDates.CalendarDate)) [NameOfDay]
FROM cteAllDates
WHERE DATEADD(d,1,cteAllDates.CalendarDate) < #DateRangeEnd
)
, cteWeekendDates AS (
SELECT CalendarDate
FROM cteAllDates
WHERE NameOfDay IN ('Saturday','Sunday')
)
, ctePublicHolidays AS (
SELECT PublicHolidayDate
FROM #PublicHolidaysTable
WHERE DATENAME(dw, PublicHolidayDate) NOT IN ('Saturday', 'Sunday')
)
, cteOrders AS (
SELECT OrderNum
, OrderDate
, CASE WHEN DATEPART(hh, OrderDate) >= 12 THEN DATEADD(dd, 1, OrderDate)
ELSE OrderDate
END [AdjustedOrderDate]
, CASE WHEN DeliveryDate IS NOT NULL THEN DeliveryDate
ELSE GETDATE()
END [DeliveryDate]
FROM #OrderTable
)
SELECT o.OrderNum
, o.OrderDate
, o.DeliveryDate
, DATEDIFF(DAY, o.AdjustedOrderDate, o.DeliveryDate) [TotalDayCount]
, (SELECT COUNT(*) FROM cteWeekendDates w
WHERE w.CalendarDate BETWEEN o.AdjustedOrderDate AND o.DeliveryDate) [WeekendDayCount]
, (SELECT COUNT(*) FROM ctePublicHolidays h
WHERE h.PublicHolidayDate BETWEEN o.AdjustedOrderDate AND o.DeliveryDate) [HolidayCount]
, DATEDIFF(DAY, o.AdjustedOrderDate, o.DeliveryDate)
- (SELECT COUNT(*) FROM cteWeekendDays w
WHERE w.CalendarDate BETWEEN o.AdjustedOrderDate AND o.DeliveryDate)
- (SELECT COUNT(*) FROM ctePublicHolidays h
WHERE h.PublicHolidayDate BETWEEN o.AdjustedOrderDate AND o.DeliveryDate) [WorkingDays]
FROM cteOrders o
WHERE o.OrderDate BETWEEN #DateRangeBegin AND #DateRangeEnd
OPTION (MaxRecursion 500)
Results from the above query using the test data...
What I'd probably do is simplify the above by adding a Calendar table populated with sufficiently wide date ranges. Then I'd take some of the CTE statements and turn them into views.
I think specifically valuable to you would be a view that gets you the work days without weekends or holidays. Then you could just simply get the date difference between the two dates and count the work days in the same range.

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