Extract or Group by End of Year in SQL - sql-server

Using this date range 02/03/2014 - 03/20/2016 how to generate this kind of result using sql
02/03/2014 - 12/31/2014
01/01/2015 - 12/31/2015
01/01/2016 - 03/20/2016

We can achieve this by building a recursive CTE.
Query
declare #startdate as date = '01/01/2014';
declare #enddate as date = '03/20/2016';
with dates as(
select dt = dateadd(yy, datediff(yy, 0, #startdate) + 1, -1)
where dateadd(yy, 1, #startDate) <= #endDate
union all
select dateadd(yy, 1, dt)
from dates
where dateadd(yy, 1, dt) <= #endDate
)
select cast(dt as date) as dt
from dates
union
select #enddate;
###Find a working demo here###

select max(date_column) MaxDateYearWise,datepart(YYYY,date_column) Year
into #dt
from date_range_table
group by datepart(YYYY,date_column)
select MaxDateYearWise from #dt
drop table #dt
--- Above query might give you the required result.

Related

Get working days,hours,minutes between two dates in sql server

Input
startdate - 2020-05-01 10:05:07.000
enddate - 2020-05-18 12:08:07.000
Expected Output
12D:02H:03M
I need output like aobve which is having hours minutes with days
Iam having query from which iam getting only working days ,below is the query
SELECT (DATEDIFF(dd, receive_date, GETDATE()) + 1)
-(DATEDIFF(wk, receive_date, GETDATE()) * 2)
-(CASE WHEN DATENAME(dw, receive_date) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, GETDATE()) = 'Saturday' THEN 1 ELSE 0 END) from email
other query i have like this
select dbo.fn_WorkDays(receive_date, getdate() ) from email
You could break it down to total seconds and then pull out the parts you need.
EDIT
Ok, I see now that you need to use only weekdays. I am certain there is a more eloquent way to do this, but this should give you a start. I would imagine using a calendar table might make it easier.
I made it so that if one of the start or end dates started on a weekend the calculation should still be correct.
Consider the following:
DECLARE #startdate as datetime = '2020-05-01 10:05:07.000'
DECLARE #enddate as datetime = '2020-05-18 12:08:07.000'
;WITH CTE AS
(
SELECT #startDate stDate, DATEADD(second, -1, DATEADD(day, DATEDIFF(day, 0, #startdate)+1, 0)) EndDate
UNION ALL
SELECT
CASE WHEN DATEADD(day,1,stDate) < DATEADD(dd, 0, DATEDIFF(dd, 0, #enddate))
THEN DATEADD(dd, 0, DATEDIFF(dd, 0, DATEADD(day,1,stDate) ))
ELSE #enddate
END,
CASE WHEN DATEADD(day,1,stDate) < DATEADD(dd, 0, DATEDIFF(dd, 0, #enddate))
THEN DATEADD(second, -1, DATEADD(day, DATEDIFF(day, 0, DATEADD(day,1,stDate))+1, 0))
ELSE #enddate
END EndDate
FROM CTE
WHERE DATEADD(day,1,stDate) <= #enddate
)
,
ctSeconds as
(
SELECT COUNT(*) DayCount,MIN(stDate) stDate, MAX(EndDate) EndDate
from CTE
WHERE DATENAME(dw,stDate) NOT IN ('SATURDAY', 'SUNDAY')
)
SELECT
FORMAT(DayCount, '00') + 'D:'
+ FORMAT ( (TotalSeconds % 86400) / 3600,'00') + 'H:'
+ FORMAT ( (TotalSeconds % 3600) / 60, '00') + 'M' AS SPAN
FROM
(
SELECT DATEDIFF(SECOND,stDate, EndDate) TotalSeconds, DayCount from ctSeconds
) x
RESULT
SPAN
12D:02H:03M
Check below query, It will help you
declare #startDate as datetime = '2020-05-02 15:05:06.000'
,#endDate as datetime = '2020-05-18 12:08:07.000'
-- Minutes calculation START
declare #startRemainingMin int=datediff(SECOND,cast('1900-01-01' as time),cast(#startDate as time))
,#endRemainingMin int=datediff(SECOND,cast('1900-01-01' as time),cast(#endDate as time))
,#diffMin int
set #diffMin = #endRemainingMin-#startRemainingmin
-- Uncount if #endDate is sunday or saturday
if(datename(DW,#endDate)='Sunday' or datename(DW,#endDate)='Saturday')
begin
select #diffMin=-1*#startRemainingmin
end
-- Uncount if #startDate is sunday or saturday
if(datename(DW,#startDate)='Sunday' or datename(DW,#startDate)='Saturday')
begin
select #diffMin=#endRemainingMin
end
--Minutes calculation END
if(#diffMin<0)
begin
select #diffMin=86400+#diffMin
end
;with cteAllDate as(
select #startDate as dt
union all
select
dt+1
from cteAllDate where dateadd(day,1,dt)<=#endDate
)
select cast(count(1)-sum(iif((datename(DW,dt)='Sunday' or datename(DW,dt)='Saturday'),1,0 )) as varchar(5)) + 'D:'
+ format ((#diffMin/3600),'00') + 'H:'
+ format ( (#diffMin%3600/60), '00') + 'M:'
+ format ( (#diffMin%60), '00') + 'S' as result
from cteAllDate
Output:
result
10D:12H:08M:07S

Recursive Start of Week Query with SUM

I am looking to get the sum of hours worked by week for n weeks in a single result. I came across this little gem that will provide a list of weeks going back n weeks from the current day using a recursive query.
DECLARE #dt DATE = '1900-01-01';
declare #startDate datetime , #endDate datetime
set #startDate = DATEADD(WEEK, DATEDIFF(WEEK, #dt, CURRENT_TIMESTAMP)-10, #dt)
set #endDate = DATEADD(WEEK, DATEDIFF(WEEK, #dt, CURRENT_TIMESTAMP)-1, #dt)
;with T(startday) as
(
select #startDate as startday
union all
select startday + 7
from T
where startday < #endDate
)
select startday as [StartDate], DATEADD(DD, 7, startday) AS [EndDate] from T
If I could use a similar recursive query that would be great. Other wise, I can build a big query with a union of each date range. I have spent more time than I would like to admit on this.
If I try.
DECLARE #monDT DATE = '1900-01-01';
DECLARE #startDate DATETIME , #endDate DATETIME
SET #startDate = DATEADD(WEEK, DATEDIFF(WEEK, #monDT, CURRENT_TIMESTAMP)-10, #monDT)
SET #endDate = DATEADD(WEEK, DATEDIFF(WEEK, #monDT, CURRENT_TIMESTAMP), #monDT)
;WITH T(startDay, endDay, StartDateTime, FinishedDateTime, ActualDurationHours)
AS (
SELECT
#startDate AS startDay,
#endDate AS endDay,
[WorkOrderTrade].[StartDateTime],
[WorkOrderTrade].[FinishedDateTime],
[WorkOrderTrade].[ActualDurationHours]
FROM [WorkOrderTrade]
WHERE [WorkOrderTrade].[TradeContactID] = 783
AND [WorkOrderTrade].[StartDateTime] > #startDate
AND [WorkOrderTrade].[FinishedDateTime] < #endDate
UNION ALL
SELECT
startDay + 7,
endDay,
StartDateTime,
FinishedDateTime,
ActualDurationHours
FROM T
WHERE startDay < #endDate
)
SELECT TOP (100)
startDay,
DATEADD(DD, 7, startday) AS endDay,
SUM(ActualDurationHours)
FROM T
GROUP BY startDay, endDay
It SUMs the total hours across the whole date range as per the recursive portion of the query. I need to come up with a way of filtering the hours in that recursive portion based on the startDay and endDay of each week. Something like the following would be good but you are not allowed to accumulate in the recursive portion.
SELECT
startDay + 7,
StartDateTime,
FinishedDateTime,
(SELECT SUM(ActualDurationHours) FROM [WorkOrderTrade] WHERE [WorkOrderTrade].[TradeContactID] = 783 AND (StartDateTime > startDay AND FinishedDateTime < DATEADD(DD, 7, startDay)))
FROM T
WHERE startDay < #endDate
Is there a way or do I need to build a large UNION query?
Persistence pays off but I had to go out of that box that I was stuck in and use a temporary table and a WHILE loop.
DECLARE #monDT DATE = '1900-01-01';
DECLARE #startDate DATETIME , #endDate DATETIME, #startOfWeek DATETIME
SET #startDate = DATEADD(WEEK, DATEDIFF(WEEK, #monDT, CURRENT_TIMESTAMP)-10, #monDT)
SET #endDate = DATEADD(WEEK, DATEDIFF(WEEK, #monDT, CURRENT_TIMESTAMP)+1, #monDT)
SET #startOfWeek = #startDate
CREATE TABLE #tmpDuration (
StartDate DATETIME,
EndDate DATETIME,
LoggedHours NUMERIC(18,7)
)
WHILE #startOfWeek < #endDate
BEGIN
INSERT INTO #tmpDuration
SELECT
#startOfWeek,
DATEADD(DD, 7, #startOfWeek),
SUM([WorkOrderTrade].[ActualDurationHours])
FROM [WorkOrderTrade]
WHERE [WorkOrderTrade].[TradeContactID] = 783
AND [WorkOrderTrade].[StartDateTime] > #startOfWeek
AND [WorkOrderTrade].[StartDateTime] < DATEADD(DD, 7, #startOfWeek)
SET #startOfWeek = DATEADD(DD, 7, #startOfWeek)
END
SELECT * FROM #tmpDuration
DROP TABLE #tmpDuration

How to get last six month of data from DB using SQL Server?

I have tried many different queries that already given here, but it also shows previous year data, for example, if use this query
Dateadd(Month, Datediff(Month, 0, DATEADD(m, -6, current_timestamp)), 0)
or
DATEADD(m, -6, current_timestamp)
These will result in the last six months. In my case, I want to print the last six month data. But the problem is if there is a data with the same date and different in the year will also result with these query eg (the above query returns the result of '2018-03-27 10:04:52.537' and if there is a data with '2017-03-27 10:04:52.537' will also come with the result). Can anyone help me?
here is my query
DECLARE #date6MonthAgo DATETIME = DATEADD(m, -6, current_timestamp)
DECLARE #totalCount INT = (SELECT COUNT(*)
FROM [PSA].[ProductionOrder]
WHERE CreatedDate >= #date6MonthAgo)
DECLARE #openCount INT = (SELECT COUNT(*)
FROM [PSA].[ProductionOrder]
WHERE DocumentStatusCode=7
AND CreatedDate >= #date6MonthAgo )
SELECT #date6MonthAgo, #totalCount, #openCount
Try something like this, after putting in the correct IDcolumn, just to verify for yourself the dates that are being returned
DECLARE #date6MonthAgo DATETIME = DATEADD(m, -6, current_timestamp);
SELECT #date6MonthAgo;
SELECT CreatedDate, keycolumnID
FROM [PSA].[ProductionOrder]
WHERE DocumentStatusCode=7
AND CreatedDate >= #date6MonthAgo
ORDER BY CreatedDate;
You can use this for find the last 6 month data from current date,
DECLARE #fromdate as datetime, #todate as datetime
set #fromdate = (select DATEADD(month, -6, getdate()))
set #todate = getdate()
SELECT CreatedDate, keycolumnID
FROM [PSA].[ProductionOrder]
WHERE DocumentStatusCode=7
AND cast(CreatedDate as date) between cast(#fromdate as date) and cast(#todate as date)
ORDER BY CreatedDate;
If you want find last 6 month date from a specific date, so you can set that date in #fromdate and #todate parameters like this,
set #fromdate = (select DATEADD(month, -6, #Yourdate))
set #todate = #Yourdate

How to check already date range inserted per month into db using sql query

How to check already date range inserted per month into db using sql query
DECLARE #TODAY DATETIME
DECLARE #STARTDATE DATETIME,#ENDATE DATETIME
SET #STARTDATE= DATEADD(mm, DATEDIFF(mm, 0, GETDATE()), 0)
SET #ENDATE= DATEADD (dd, -1, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0))
IF NOT EXISTS (select date from table where date between #STARTDATE and #ENDATE)
IF (#D_INVOICE_DATE >= #TODAY)
BEGIN
---INSERT--
END
ELSE
BEGIN
PRINT 'EXISTS'
END
but again and again inserted in db
my required is per month only one record inserted in db based month wise
Convert datetime to date, but this kill using index
IF NOT EXISTS (select * from table where CAST(date as date) between #STARTDATE and #ENDATE)
SET #ENDATE= DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0)
IF NOT EXISTS (select * from table where date >= #STARTDATE and date < #ENDATE

How to declare dates in SQL multiple value

I am trying to create my SQL syntax so that we can have versatile input. I figured out how to do it for one set date and it worked.
my syn is:
DECLARE #MyDay AS VARCHAR(50);
DECLARE #NextDay AS VARCHAR(50);
SET #MyDay = '8/30/2016';
SET #NextDay = DATEADD(d, 1, #MyDay);
However, I'm stuck with how to do it for multiple dates. Ideally I would like to put in a range of date, and from that it will scan the records, i.e. set range between oct 1st and oct 5th.
I'm using SQL Server Management Studio 2008
If you just want a series of days and next days between 8/30/16 and 9/5/16, you can use a derive table method like below.
declare #n int;
declare #StartDate datetime, #EndDate datetime;
set #n = 5;
set #StartDate = '20160830';
set #EndDate = dateadd(day, #n, #StartDate);
select cast(dateadd(day, number, #StartDate) as date) as MyDate,
cast(dateadd(day, number + 1, #StartDate) as date) as MyNextDate
from
(select distinct number from master.dbo.spt_values
where name is null
) n
where dateadd(day, number, #StartDate) < #EndDate;
Alternately you can use a temp table, table variable to store your dates, or a cte as well.
A recursive cte imlementation example is given below. Please note you would want to set MAXRECURSION option if you have a long date range as default for max recursion is 100.
declare #n int;
declare #StartDate datetime, #EndDate datetime;
set #n = 5;
set #StartDate = '20160830';
set #EndDate = dateadd(day, #n, #StartDate);
;with DateSeq as
(
select cast(#StartDate as date) as MyDate
union all
select dateadd(day , 1, MyDate) AS MyDate
from DateSeq where dateadd (day, 1, MyDate) < #EndDate
)
select MyDate, dateadd(day , 1, MyDate) AS NextDate
from DateSeq;
A temp table implementation example is as below.
declare #MyDateRange table(MyDate date);
Insert into #MyDateRange values('8/30/2016')
Insert into #MyDateRange values('9/1/2016')
Insert into #MyDateRange values('9/2/2016')
Insert into #MyDateRange values('9/3/2016')
Insert into #MyDateRange values('9/4/2016')
select MyDate, dateadd(day, 1, MyDate) as NextDate from #MyDateRange

Resources