Get the average Hour period from a selected Date range - sql-server

I have a order table which happens to have a column of DataType "Datetime" which contains Date and Time of the arrival of product to the Company(customer) and i have multiple type of users
their types are like:
Employee, CompanyOwners(customers),Dispatchers..etc
I have managed to get the date range of orders against to the specific user who is the owner of the company using the following T-SQL query below:
declare #username varchar(130), #DateFrom varchar(10), #DateTo varchar(10)
set #username = 'chabow';set #DateFrom='4/01/2018';set #DateTo='6/30/2018'
;with cte as (
select count(o.ArrivalDate) as orders_count, cast(o.ArrivalDate as Date) as ArrivalDate
from view_MembershipUsers msu
inner join XrefCompanyUsers rfu on msu.UserName = rfu.UserName
inner join Company f on f.CompanyID = rfu.CompanyID
inner join orders o on o.CompanyID = f.CompanyID
where msu.UserName = #username and
(o.ArrivalDate >= #DateFrom and o.ArrivalDate <= #DateTo)
group by cast(o.ArrivalDate as Date)
)
select *,
(select max(orders_count)+2 from cte) as Total
from cte
order by ArrivalDate
What i actually need to retrieve is the Average hour of arrival of product along with the data i have retrieved using above query from selected date range. I am clueless to how i can get the average in hours from this date range without getting the date difference, because i need to read "date" of every row to get the most possible accurate average hour.
I have extracted some sample dates for ease in order for you guys to help me.
create table SelectedData
(ArrivalDate date, ActualDateTime datetime)
insert into SelectedData values
('2018-04-01','2018-04-01 20:45:00.000'),
('2018-04-04','2018-04-04 19:00:00.000'),
('2018-04-05','2018-04-05 14:00:00.000'),
('2018-04-05','2018-04-05 14:23:00.000'),
('2018-04-05','2018-04-05 18:30:00.000'),
('2018-04-06','2018-04-06 12:30:00.000'),
('2018-04-06','2018-04-06 18:08:00.000')
declare #DateFrom varchar(10), #DateTo varchar(10)
set #DateFrom='4/01/2018';set #DateTo='6/30/2018'
select *
from SelectedData
order by ArrivalDate
Thanks and regards.

Change your type to DateTime, and not date. Like this :
drop table SelectedData
create table SelectedData
(ArrivalDate date, ActualDateTime datetime)
insert into SelectedData values
('2018-04-01','2018-04-01 20:45:00.000'),
('2018-04-04','2018-04-04 19:00:00.000'),
('2018-04-05','2018-04-05 14:00:00.000'),
('2018-04-05','2018-04-05 14:23:00.000'),
('2018-04-05','2018-04-05 18:30:00.000'),
('2018-04-06','2018-04-06 12:30:00.000'),
('2018-04-06','2018-04-06 18:08:00.000')
declare #DateFrom varchar(10), #DateTo varchar(10)
set #DateFrom='4/01/2018';set #DateTo='6/30/2018'
select avg(datePart(hour, ActualDateTime))
from SelectedData
--order by ArrivalDate
And then get the datepart of hours from the date, and then the average of that.

Related

Can I "left join" days between 2 dates in sql server?

There is a table in SQL Server where data is entered day by day. In this table, data is not filled in some days.
Therefore, there are no records in the table.
Sample: dataTable
I need to generate a report like the one below from this table.
Create a table with all the days of the year. I know that I can output a report by "joining" the "dataTable" table.
But this solution seems a bit strange to me.
Is there another way?
the code i use for temp date table
CREATE TABLE tempDate (
calendarDate date,
PRIMARY KEY (calendarDate)
)
DECLARE
#start DATE= '2021-01-01',
#dateCount INT= 730,
#rowNumber INT=1
WHILE (#rowNumber < #dateCount)
BEGIN
INSERT INTO tempDate values (DATEADD(DAY, #rowNumber, #start))
set #rowNumber=#rowNumber+1
END
GO
select * from tempDate
This is how I join using this table
SELECT
*
FROM
tempDate td WITH (NOLOCK)
LEFT JOIN dataTable dt WITH (NOLOCK) ON dt.reportDate = td.calendarDate
WHERE
td.calendarDate BETWEEN '2021-09-05' AND '2021-09-15'
Create a table with all the days of the year. I know that I can output a report by "joining" the "dataTable" table.
This is the way. You can generate that "table" on the fly if you really want to, but normally the best way is to simply have a calendar table.
You can use common expression tables for dates. The code you need:
IF(OBJECT_ID('tempdb..#t') IS NOT NULL)
BEGIN
DROP TABLE #t
END
CREATE TABLE #t
(
id int,
dt date,
dsc varchar(100),
)
INSERT INTO #t
VALUES
(1, '2021.09.08', 'a'),
(1, '2021.09.09', 'b'),
(1, '2021.09.12', 'c')
DECLARE #minDate AS DATE
SET #minDate = (SELECT MIN(dt) FROM #t)
DECLARE #maxDate AS DATE
SET #maxDate = (SELECT MAX(dt) FROM #t)
;WITH cte
AS
(
SELECT #minDate AS [dt]
UNION ALL
SELECT DATEADD(DAY, 1, [dt])
FROM cte
WHERE DATEADD(DAY, 1, [dt])<=#maxDate
)
SELECT
ISNULL(CAST(t.id AS VARCHAR(10)), '') AS [id],
cte.dt AS [dt],
ISNULL(t.dsc, 'No record has been entered in the table.') AS [dsc]
FROM
cte
LEFT JOIN #t t on t.dt=cte.dt
The fastest method is to use a numbers table, you can get a date list between 2 dates with that:
DECLARE #Date1 DATE, #Date2 DATE
SET #Date1 = '20200528'
SET #Date2 = '20200625'
SELECT DATEADD(DAY,number+1,#Date1) [Date]
FROM master..spt_values
WHERE type = 'P'
AND DATEADD(DAY,number+1,#Date1) < #Date2
If you go go in LEFT JOIN this select, whit your table, you have the result that you want.
SELECT *
FROM (SELECT DATEADD(DAY,number+1,#Date1) [Date]
FROM master..spt_values WITH (NOLOCK)
WHERE type = 'P'
AND DATEADD(DAY,number+1,#Date1) < #Date2 ) as a
LEFT JOIN yourTable dt WITH (NOLOCK) ON a.date = dt.reportDate
WHERE td.[Date] BETWEEN '2021-09-05' AND '2021-09-15'

how to get dates between two dates('FromDate and ToDate') and if we have the null value In Todate we should change to getdate() In Todate?

I have a Table With PatientID and FromDate and Todate,I want to generate the dates between these two dates and one more main important scenario is,If we have Null in the Todate We have to Convert that Null Into Getdate() and then get the Dates and "This query should be done without using 'CTE' AND 'While'."
Declare #Temp AS TABLE
(
PatientID INT,
FromDate DATE,
ToDate DATE
)
INSERT INTO #Temp VALUES(3,'2014-05-16','2014-05-16')
INSERT INTO #Temp VALUES(3,'2014-05-16','2014-05-22')
INSERT INTO #Temp VALUES(3,'2014-05-22',NULL)
SELECT * FROM #Temp

Get data from the last day of the month without the use of loops or variables

I wrote a query that should select the last record of each month in a year. I'd like to create a View based on this select, that I could run later in my project, but unfortunately I can't use any while loops or variables in a view command. Is there a way to select all these records - last days of a month in a View that I can use later?
My desired effect of the view:
The query that I'm trying to implement in a view:
DECLARE #var_day01 DATETIME;
DECLARE #month int;
SET #month = 1;
DROP TABLE IF EXISTS #TempTable2;
CREATE TABLE #TempTable2 (ID int, date datetime, INP2D float, INP3D float, ID_device varchar(max));
WHILE #month < 13
BEGIN
SELECT #var_day01 = CONVERT(nvarchar, date) FROM (SELECT TOP 1 * FROM data
WHERE DATEPART(MINUTE, CONVERT(nvarchar, date)) = '59'
AND
MONTH(CONVERT(nvarchar, date)) = (CONVERT(nvarchar, #month))
ORDER BY date DESC
) results
ORDER BY date DESC;
INSERT INTO #TempTable2 (ID, date, INP2D,INP3D,ID_device)
SELECT * FROM data
WHERE DATEPART(MINUTE, CONVERT(nvarchar, date)) = '59'
AND
MONTH(CONVERT(nvarchar, date)) = (CONVERT(nvarchar, #month))
AND
DAY(CONVERT(nvarchar, date)) = CONVERT(datetime, DATEPART(DAY, #var_day01))
ORDER BY date DESC
PRINT #var_day01
SET #month = #month +1;
END
SELECT * FROM #TempTable2;
If you are actually just after the single most recent row for each month, there is no need for a while loop to achieve this. You just need to identify the max date value for each month and then filter your source data for those for those rows.
One way to achieve this is via a row_number window function:
declare #t table(id int,dt datetime2);
insert into #t values(1,getdate()-40),(2,getdate()-35),(3,getdate()-25),(4,getdate()-10),(5,getdate());
select id
,id_device
,dt
from(select id
,id_device
,dt
,row_number() over (partition by id_device, year(dt), month(dt) order by dt desc) as rn
from #t
) as d
where rn = 1;
You can add a simple where to your select statement, in where clause you will add one day to the date field and then select the day from the resultant date. If the result date is 1 then only you will select that record
the where clause for your query will be : Where Day(DATEADD(d,1,[date])) = 1

Pivot Activity Code Days Months

I am trying to get the activity codes for specific days to show the 31 days in every month of the year for a specific staff member.
If the staff member was present, sick, holiday leave, etc... I want those activity codes to display based on the output below for a year act_date range.
Thanks!
Pivot Activity Code Days Months
This can be achieved with pivoting. Here you can enter the staff id in the query to fetch the results for that particular staff.
--create table
create table staff_info
(
staffId int,
actDate datetime,
activityCode int
)
--insert values
insert into staff_info values
(2699, '01/02/2017', 101),
(2699, '05/14/2017', 303),
(2699, '08/06/2017', 101),
(1927, '10/25/2017', 105)
--actual solution
select * from
(
select staffId, day(actDate) as act_day,month(actDate) as actual_month,
activityCode
from staff_info
where staffId=2699 ----- enter the staff id here
) src
pivot
(
sum(activityCode)
for act_day in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],
[14],[15],
[16],[17],[18],[19],[20],[21],[22],[23],[24],[25],[26],[27],[28],[29],[30],
[31]
)
) p
Result:
Firstly, create a function which would give the date values for a specific range
CREATE FUNCTION [dbo].[GetAllDatesBetweenRange]
(
#FromDate DATE
,#ToDate DATE
)
RETURNS #Dates TABLE
(
DateVal DATE
)
AS
BEGIN
;WITH CTE
AS
(
SELECT #FromDate AS FromDate
UNION ALL
SELECT DATEADD(DD,1,FromDate)
FROM CTE
WHERE FromDate < #ToDate
)
INSERT INTO #Dates
SELECT FromDate FROM CTE
OPTION (MAXRECURSION 0)
RETURN;
END
GO
Use the below dynamic query to pivot for the specific date range
DECLARE #Sql NVARCHAR(MAX);
DECLARE #DateVal NVARCHAR(MAX);
SELECT #DateVal = STUFF((SELECT ',['+CAST(DateVal AS NVARCHAR(50))+']'
FROM [dbo].[GetAllDatesBetweenRange]('2017-01-01','2017-12-31')
FOR XML PATH('')),1,1,'')
SET #Sql = '
;WITH CTE
AS
(
SELECT Res1.STAFF_ID
,Res2.DateVal
,Res1.ACTIVITY_CODE
FROM [dbo].[GetAllDatesBetweenRange](''''2017-01-01'''',''''2017-12-31'''') Res1
LEFT JOIN TableA A ON A.ACT_DATE = Res1.DateVal
)
SELECT STAFF_ID
,*
FROM CTE
PIVOT
(
MAX(ACTIVITY_CODE)
FOR DateVal IN ('+#DateVal+')'+'
)'
EXEC SP_EXECUTESQL #Sql

SQL Server CTE For Each Date

I am stuck at this point where I need to get a report for a screen in my project.
The user input is start date and end date...
I need the "closed task count" for each day between those values. If there are no tasks on some dates, the count should return "0". Here I am so far, but I really don't understand what I am doing wrong. Please help!
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
ALTER PROCEDURE APP.GET_TASK_ENTRY_ACTIVE_GRAPH
(
#START_DATE DATETIME,
#END_DATE DATETIME
)
AS
BEGIN
SET NOCOUNT ON
CREATE TABLE #TMP_TASK_VALS
(
DATE_VALUE DATETIME,
VAL INT
)
INSERT INTO #TMP_TASK_VALS
(
DATE_VALUE, VAL
)
SELECT CONVERT(DATETIME, TASK_CLOSING_DATE), COUNT(1) FROM APP.TASK_ENTRIES (NOLOCK)
WHERE TASK_CLOSING_DATE BETWEEN #START_DATE AND #END_DATE
GROUP BY TASK_CLOSING_DATE
--ORDER BY TASK_CLOSING_DATE DESC
--SELECT * FROM #TMP_TASK_VALS
;WITH CTE_DAILY(DAY) AS
(
SELECT #START_DATE AS DAY
UNION ALL
SELECT DAY + 1 FROM CTE_DAILY
WHERE DAY < #END_DATE
)
SELECT CTE_DAILY.DAY, COUNT(VAL) FROM CTE_DAILY WITH (NOLOCK) LEFT JOIN #TMP_TASK_VALS WITH (NOLOCK) ON #TMP_TASK_VALS.DATE_VALUE = CTE_DAILY.DAY
GROUP BY CTE_DAILY.DAY
DROP TABLE #TMP_TASK_VALS
END
GO
/*
exec APP.GET_TASK_ENTRY_ACTIVE_GRAPH '2015-08-10', '2015-08-16'
*/
The result is like, I have all the dates continuosly, but the value (count) is all zero.
Cheers.
I observed that you are converting TASK_CLOSING_DATE to datetime in first query, but not while using BETWEEN.I see some datatype mismatch. Please try to convert while joining with CTE too.
EDIT: As per OP's feedback the issues is with conversion of date and datetime fields.
OP's Comment : Converting my DATETIME to DATE totally solved this

Resources