Select time difference in minutes for this months portion only - sql

Cant figure out what im doing wrong:
I have a table that has a start time and end time column and im trying to figure out the sum of time in minutes for this months portion only.
Eg.
Start date: 27-02-13
End Date: 03-03-13
Over all minutes= 5760
Minutes for March only: 4320
This is my query but its not working properly, i tried to add a where clause to look back the last two months for pervious time entrys. What am I doing wrong?
SELECT
isnull((Sum(DATEDIFF(minute,
CASE when datetime5 < dateadd(mm,datediff(mm,0,GetDate()), 0)
THEN dateadd(mm,datediff(mm,0,GetDate()), 0)
ELSE datetime5 END,
CASE when datetime6 > dateadd(mm,datediff(mm,0,GetDate())+1, 0)
THEN dateadd(mm,datediff(mm,0,GetDate())+1, 0)
ELSE datetime6 END))/60.0),0 )
as Minutes , 0
FROM AllUserData
WHERE tp_ListID in (select tp_ID from Lists where tp_Title = 'D1 Downtime')
and datetime5 >=dateadd(mm,datediff(mm,0,GetDate())-2, 0);

See this SQL Fiddle.
with month_start_finish (month_start, month_finish) as
(
-- here you get the beginning of the current month and the next month
-- needed for filters and calculations
select
dateadd(month, datediff(month, 0, getdate()), 0),
dateadd(month, datediff(month, 0, getdate()) + 1, 0)
)
select start_date, finish_date,
-- here you calculate your minutes
datediff(minute,
case when start_date > month_start then start_date else month_start end,
case when finish_date < month_finish then finish_date else month_finish end
) as minutes_in_this_month
from test, month_start_finish
where start_date < month_finish -- here you remove any periods that
and finish_date > month_start -- are not related to the current month
Note how it works correctly even if the the period is longer than a month.

Select all records that end after the beginning of this month.
Then, the portion of each record that is in this month can be obtained with something like this (pseudo-code):
end - max(start,start_of_this_month)
Take the start of the period or the start of this month, whichever is later.
This should help you simplify your query, I think. Here is the basic idea (pseudo-code again, as I don't know the nuances of SQL Server date operations).
select sum(elapsed_time) from (
select end - max(start,start_of_this_month) as elapsed_time
from your table
where end > start_of_this_month
) time_periods

Related

Calculate due date and exclude working/business days SQL

I would like to calculate a due date.
If the start date is 30/12/2020, I need to count 20 working days from start date and display the date for the 20th working date from start date.
For example if the start date is 30/12/2020 must give me 28/01/2021 (excludes saturdays and sundays and finds the 20th working day from 30/12/2020).
But I am unable to exclude the weekends.
SELECT
DATEADD(DAY,20,CAST(CAST('2020-12-30' AS DATE) AS DATETIME))
-(CASE WHEN DATENAME(dw,'2020-12-30') = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw,'2020-12-30') = 'Saturday' THEN 1 ELSE 0 END) AS DueDate
thanks
Your best pick would be to build a calendar table, with a boolean flag that indicates whether each day is a working day or not. Then you would just do something like:
select dt
from calendar
where dt >= '20201231' and is_working_day = 1
order by dt
offset 19 rows fetch next 1 row only
The way your question is asked, however, one option enumerates the days in a subquery until the count of working days is reached:
declare #dt date = '20201231';
declare #no_days int = 20;
with cte as (
select #dt as dt, #no_days as no_days
union all
select dateadd(day, 1, dt),
case when datename(weekday, dt) in ('Saturday', 'Sunday')
then no_days
else no_days - 1
end
from cte
where no_days > 1
)
select max(dt) as res from cte
If you don't care about holidays, then the 20th working day is exactly 28 days later. So you can use:
dateadd(day, 28, '2020-12-30')
Note: This assumes that the starting date is a working day.

SQL Server Group a promotion by last 24 hours, last week and last month and sort by week descending

I'm trying to look at how successful different promotions have been in the last 24 hours, week and month. To get the amount by promotion for the last 24 hours I've used this code but I don't understand how to get another two columns for the last week and the last month. And then finally I want to order it by the amount in the last week descending. I want to be able to run this query at any point during the month. Please help me.
SELECT Promotion
, Sum(Amount) AS Last_24
FROM dbo.CustomerPayment
WHERE Started >= DATEADD(day, - 1, GETDATE())
GROUP
BY Promotion
You can do it in a single query :
SELECT Promotion
, Sum(CASE WHEN Started >= DATEADD(day, -1, GETDATE()) THEN Amount ELSE 0 END) AS Last_24
, Sum(CASE WHEN Started >= DATEADD(day, -7, GETDATE()) THEN Amount ELSE 0 END) AS Last_Week
, Sum(Amount) AS Last_Month
FROM dbo.CustomerPayment
WHERE Started >= DATEADD(day, - 31, GETDATE())
GROUP
BY Promotion
ORDER BY Last_Week DESC
Note that this part :
WHERE Started >= DATEADD(day, - 31, GETDATE())
as te be clarified following your own interpretation of "Last Month" concept.
Use conditional aggregation -- that is, move the conditions to the select:
SELECT Promotion,
SUM(case when Started >= DATEADD(day, - 1, GETDATE()) then Amount end) AS Last_1_day,
SUM(case when Started >= DATEADD(day, - 7, GETDATE()) then Amount end) AS Last_7_day,
. . .
FROM dbo.CustomerPayment
GROUP BY Promotion;
One possible issue, though. GETDATE() -- despite its name -- returns a time component to the date. I suspect that you might actually want to treat this as a date, not a datetime:
SELECT Promotion,
SUM(case when Started >= DATEADD(day, - 1, CONVERT(DATE, GETDATE())) then Amount end) AS Last_1_day,
SUM(case when Started >= DATEADD(day, - 7, CONVERT(DATE, GETDATE())) then Amount end) AS Last_7_day,
. . .
FROM dbo.CustomerPayment
GROUP BY Promotion;
I was looking for month / week. Not 7 / 30 days.
If you wish those, just use variables to have that query readable.
declare #monthstart date,
#weekstart date
;
select #monthstart=datefromparts(year(current_timestamp),month(current_timestamp),1)
select cast(DATEADD(d,1-DATEPART(WEEKDAY,current_timestamp),CURRENT_TIMESTAMP) as date) as Sunday,
cast(DATEADD(d,2-case when DATEPART(WEEKDAY,current_timestamp)=1 then 8 else DATEPART(WEEKDAY,current_timestamp) end,CURRENT_TIMESTAMP) as date) as Monday
;

What is -1 and 0 doing in date add function?

dateadd(mm, DATEPART(MONTH, DATE) - 1, 0) + DATEPART(DAY, DATE) - 1
OUTPUT date is in the year for example 1990-12-02 00:00:00:000
Full query is below:
SELECT dateadd(yy, (
DATEPART(YEAR, GETDATE()) + (
CASE
WHEN DATEPART(MONTH, GP_DATE) > 10
THEN 0
ELSE 1
END
) - 1900
), 0) + dateadd(mm, DATEPART(MONTH, GP_DATE) - 1, 0) + DATEPART(DAY, GP_DATE) - 1 GP_DATE
from table
I am trying to convert this query into snowflake syntax and snowflake syntax dateadd function does not allow 1, 0.
In SQL Server, there are some rather ugly implicit conversions available between datetimes and integers.
0, when converted to a date, becomes 1900-01-01.
You're also allowed to do maths on dates. Adding or subtracting 1 adds or subtracts 1 day from the date. Putting these facts together, we have:
dateadd(yy, (
DATEPART(YEAR, GETDATE()) + (
CASE
WHEN DATEPART(MONTH, GP_DATE) > 10
THEN 0
ELSE 1
END
) - 1900
), 0)
Which is taking the current year, and subtracting 1900 from it (or 1899 if the month is less than 11, for whatever reason). We then take that number and add it back to the date 0 (which as stated above is 1900-01-01). The result is that we get the first of January of next year or this year, depending on the month of GP_DATE. Call this D1.
Moving on:
dateadd(mm, DATEPART(MONTH, GP_DATE) - 1, 0)
is taking the month of GP_DATE, subtracting 1 from it and adding that number of months to the date 0 (1900-01-01). The result is a the 1st of whichever month GP_DATE is in, but in 1900. Let's call this D2.
When we add D1 and D2 together, we approximately get a date of the 1st of whichever month GP_DATE is in, in either this year or next year. Note, however, that this goes wrong if the D1 year is a leap year, we get it wrong by a day for months after February.
Finally, we take DATEPART(DAY, GP_DATE) - 1, where we take the day of the month from GP_DATE, subtract 1, and add that on to our result so far. This should set the final date to be on the same day of the month as GP_DATE, except for the error mentioned above.
So, it appears that the code is trying to take GP_DATE and get the same date in either this year or next year, depending on how late in the year GP_DATE is. However, it also appears it was never tested with consideration for leap years.
A far more likely correct version of this query would be this instead:
SELECT
DATEADD(year,
DATEDIFF(year,GP_DATE,CURRENT_TIMESTAMP) +
CASE WHEN DATEPART(month,GP_DATE)>10 THEN 0 ELSE 1 END
,GP_DATE)

How to get from a date column the last date of the previous month?

I have two date columns, which takes into account only working days. A_date and E_date.
E_date is calculated adding +2 days to A_date, because that's the request
The problem is that if the day of A_date is 30th or 31st of the month, then E_date date needs to be the last day of the current month, and not the first or second working day of the next month.
i have tried eomonth function but that does not work because it would need a explicit date.
Do you have any idea how to solve it?
You can use EOMONTH() in SQLServer to get the last day of the month.
Example:
EOMONTH(A_date)
SELECT CASE WHEN dateadd(month,1+datediff(month,0,A_date),-1)< DATEADD(day, 2, A_date) THEN dateadd(month,1+datediff(month,0,A_date),-1) ELSE DATEADD(day, 2, A_date) END E_date
FOR input of 2019/09/30 output is 2019-09-30 00:00:00.000
I'm not sure what your question is. What I've understood so far is that you want the last date of the month in case when adding two days to A_Date jumps to the next month.
Why don't you use CASE WHEN and compare out the months, this way :
DECLARE #A_Date date = '2019/09/30';
DECLARE #A_Date_Month int = 0;
DECLARE #E_Date_Month int = 0;
SELECT #A_Date_Month = Month(Cast(#A_Date AS datetime));
SELECT #E_Date_Month = Month(DATEADD(day, 2, #A_Date));
SELECT CASE
WHEN #A_Date_Month = #E_Date_Month
THEN DATEADD(day, 2, #A_Date)
ELSE EOMONTH(#A_Date) END AS OUTPUTValue
Try out the above set and do let me know if it resolves your issue!
How to get from a date column the last date of the previous month?
It depends on your RDBMS, so let's take the opportunity to make a generic answer:
In Oracle:
LAST_DAY(ADD_MONTHS(mydate ,-1))
In MySQL:
LAST_DAY(mydate - INTERVAL 1 MONTH)
In SQL Server:
DATEADD(MONTH, DATEDIFF(MONTH, -1, mydate )-1, -1)
-- or simply:
EOMONTH(DATEADD(Month, -1, mydate ))
In Postgres:
date_trunc('month', now())::mydate - 1
have two date columns, which takes into account only working days. A_date and E_date. E_date is calculated adding +2 days to A_date, because that's the request
I would simply do:
(case when dateadd(day, 2, a_date) < eomonth(a_date)
then dateadd(day, 2, a_date)
else eomonth(a_date)
end) as e_date
If you truly want this only on the 30th or 31st of any given month and not the last 2 days of any month (since obviously not every month has 31 days) --
select A_date
,case when day(A_date) >= 30
then eomonth(A_date)
else dateadd("dd",2,A_date)
end as E_date
Other answers work for "last 2 days of any month".

SQL getdate issue with month

i need help on my little problem.
SELECT FORMAT(ServiceDate, 'dd-MM-yyy") AS ServiceDate
FROM Services
WHERE Day(ServiceDate) BETWEEN '1' AND Day(getdate() -2)
AND Month(ServiceDate) =
CASE
WHEN Day(getdate()) <=2
THEN Month(getdate() -1
ELSE Month(getdate())
END
AND Year(ServiceDate) = Year(getdate())
Now the problem is the first and the second of the Month.
The query don't use the last month. It shows the actual month.
I hope its clear what i need.
if we have the 01-06-2016 and i need minus 2, so the query must give me back to the day 30-05-2016
big THX
the output for today with this query
output query
Assuming you are using sql-server, you need to use DATEADD(Day, -2, GETDATE()) for subtracting 2 days from current date.
I think I understand the logic now:
If the current day is the 1st of the month, get all the records from the start of previous month, until 2 days before it ends.
If the current day is the 2nd of the month, get all the records from the start of the previous month until one day before it ends.
If the current day is the 3rd of the month or higher, get all the records from the beginning of the current month until 2 days ago.
Since you are using the FORMAT() function that was introduced in 2012 version, you can also use the EOMONTH() function that was introduced in the same version.
This function returns the date of the end of the month of the date it receives as an argument, and also have a useful optional second argument that specifies the numbers of months to add to the date passed to the function.
Using this function will allow you to write your query without using any functions on the ServiceDate column, thus enabling the use of any indexes defined on this column.
DECLARE #Now datetime = GETDATE()
SELECT FORMAT(ServiceDate, 'dd-MM-yyy') AS ServiceDate
FROM Services
WHERE (
DAY(#Now) <= 2
AND ServiceDate >= DATEADD(DAY, 1, EOMONTH(#Now, -2))
AND ServiceDate < DATEADD(DAY, -(DAY(#Now)-1), EOMONTH(#Now, -1))
)
OR
(
DAY(GETDATE()) > 2
AND ServiceDate >= DATEADD(DAY, 1, EOMONTH(#Now, -1))
AND ServiceDate < DATEADD(DAY, -2, #Now)
)
Compute enddate as 2 days before getdate() and select data in interval from enddate's first of month and enddate.
SELECT FORMAT(ServiceDate, 'dd-MM-yyy") AS ServiceDate
FROM Services
CROSS APPLY (SELECT enddate = DATEADD(D,-2,getdate()) x
WHERE ServiceDate BETWEEN DATEADD(MONTH,DATEDIFF(MONTH,0,x.enddate),0) AND x.enddate