For some reason I am struggling with the logic of what I am trying to achieve here and was wondering if any help would be forthcoming.
Please find code for the data below -
/****** Object: Table [dbo].[temp_TEST] Script Date: 09/07/2021 12:01:26 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[temp_TEST](
[TransactionId] [int] NULL,
[DateFrom] [datetime] NULL,
[DateTo] [datetime] NULL,
[totalvalue] [decimal](18, 2) NULL,
[DailyAmount] [decimal](18, 2) NULL,
[EffectiveFromDate] [datetime] NULL,
[EffectiveToDate] [datetime] NULL
) ON [PRIMARY]
GO
INSERT [dbo].[temp_TEST] ([TransactionId], [DateFrom], [DateTo], [totalvalue], [DailyAmount], [EffectiveFromDate], [EffectiveToDate]) VALUES (809228, CAST(N'2021-06-14T00:00:00.000' AS DateTime), CAST(N'2021-06-27T00:00:00.000' AS DateTime), CAST(159.16 AS Decimal(18, 2)), CAST(11.37 AS Decimal(18, 2)), CAST(N'1946-01-01T00:00:00.000' AS DateTime), CAST(N'2021-06-22T00:00:00.000' AS DateTime))
INSERT [dbo].[temp_TEST] ([TransactionId], [DateFrom], [DateTo], [totalvalue], [DailyAmount], [EffectiveFromDate], [EffectiveToDate]) VALUES (809228, CAST(N'2021-06-14T00:00:00.000' AS DateTime), CAST(N'2021-06-27T00:00:00.000' AS DateTime), CAST(159.16 AS Decimal(18, 2)), CAST(11.37 AS Decimal(18, 2)), CAST(N'2021-06-23T00:00:00.000' AS DateTime), CAST(N'2021-07-09T11:59:40.833' AS DateTime))
What I am trying to do is work out the number of days that have past between a set of dates.
So what this shows is a DateFrom and DateTo field. These are the keys dates that I want to calculate between the EffectiveFromDate and EffectiveToDate.
So what I would expect is the number of days that past between the DateFrom and DateTo....during the EffectiveFromDate and EffectiveToDate, so how many days per row have past but ONLY during the DateFrom and DateTo date.
First row - has been effective since 01/01/1946, but it ended on the 22/06/21 -that is 9 days between the DateFrom and DateTo dates. That is the 14/06 to the 22/06.
Second row - has been effective since 23/06. It's still effective hence the effectivetodate being today's date...but it's been that value since the 23/06, so that will be 5 days between the DateFrom and DateTo. Including the 23/06.
Hope I've explained myself properly.
Please check below, it should help.
You need to use ISNULL and DATEDIFF functions
SELECT DATEDIFF(day, '2021/08/25', ISNULL('2021/08/28', getdate())) AS DateDiff;
SELECT DATEDIFF(day, '2021/08/25', ISNULL(null, GETDATE())) AS DateDiff;
SELECT DATEDIFF(day, EffectiveFromDate, ISNULL(EffectiveToDate, GETDATE())) AS DateDiff
FROM YourTable
Based on new information in question, please play around with below case when query
SELECT DATEDIFF(day,
case when EffectiveFromDate > DateFrom then EffectiveFromDate else DateFrom end,
case when EffectiveToDate < DateTo then EffectiveToDate else DateTo end) AS DateDiff
FROM temp_TEST
it actually gives you 8 and 4 days, not 9 and 5 but this is how this function works, you can add +1 to include second date in counting, see below
SELECT DATEDIFF(day,
case when EffectiveFromDate > DateFrom then EffectiveFromDate else DateFrom end,
case when EffectiveToDate < DateTo then EffectiveToDate + 1 else DateTo + 1 end) AS DateDiff
FROM temp_TEST
Related
I'm struggling to think up the easiest way to get all rows/records that were create within the last month. I can build a sortof convoluted one below but is there a simplier way?
SELECT
*
FROM
MyTable
WHERE
MONTH( createdAt ) >= MONTH( GET_DATE() ) - 1
AND
YEAR( createdAt ) = YEAR( GET_DATE );
The above would work but not for December records. Any advice how to simplify this and handle December created records?
DECLARE #startOfMonth date = DATEFROMPARTS( YEAR( SYSUTCDATETIME() ), MONTH( SYSUTCDATETIME() ), 1 )
SELECT
*
FROM
myTable
WHERE
createdAt >= #startOfMonth
Or inline it (SQL Server should detect the RHS is constant so using a variable won't increase performance):
SELECT
*
FROM
myTable
WHERE
createdAt >= DATEFROMPARTS( YEAR( SYSUTCDATETIME() ), MONTH( SYSUTCDATETIME() ), 1 )
If you are looking for records WITHIN the last month I am assuming you mean the last 30 days this will work:
SELECT *
FROM myTable
where createdAt >= CAST(DATEADD(day,-30,GETDATE()) as date)
If you are actually looking for records that were in last month then this will work:
SELECT *
from myTable
WHERE createdAt >= CAST( DATEADD(month, DATEDIFF(month, -1, GETDATE()) - 2, 0) as date)
I want to get all rows 7 days prior from 01/09/2017
I know I can do
Load_DTM <= '2017-01-09' and Load_DTM >= '2017-01-02'
But can I not use DateAdd or DatePart?
i.e. DateAdd(dd, -7, '2017-01-09')
Load_DTM BETWEEN DATEADD(dd,-7,'2017-01-09') AND '2017-01-09 11:59:59'
ought to work.
You should be able to do exactly what you showed in your example:
SELECT * FROM Table WHERE DateField = DATEADD(DAY, -7, '2017-09-01')
Since running:
SELECT DATEADD(DAY, -1, GETDATE())
Gives you:
2017-03-15 19:26:29.833
I have a query to get the count of buses which travel less than 100 km per day. So I use the query in PostgreSQL
select day,count(*)as bus_count from(
SELECT date_trunc('hour',start_time)::timestamp::date as day,bus_id,sum(distance_two_points) as distance
FROM public.datatable where start_time >= '2015-09-05 00:00:00' and start_time <= '2015-09-05 23:59:59'
group by day,bus_id
) as A where distance<=250000 group by day
The query returns the result
day bus_id distance
___ ________ _________
"2015-09-05 00:00:00" 1 523247
"2015-09-05 00:00:00" 2 135114
"2015-09-05 00:00:00" 3 178560
"2015-09-05 00:00:00" 4 400071
"2015-09-05 00:00:00" 5 312832
"2015-09-05 00:00:00" 6 237075
So I now want to use this same query (achieving same results) in SAP HANA but there is no date trunc function and I also tried
SELECT EXTRACT (DAY FROM TO_DATE (START_TIME, 'YYYY-MM-DD')) "extract" as day,
bus_id, sum(distance_two_points) as distance
FROM public.datatable
where start_time >= '2015-09-05 00:00:00' and start_time <= '2015-09-05 23:59:59'
group by day,bus_id
) as A where distance<=250000 group by day
Any help is appreciated.
SELECT SERIES_ROUND('2013-05-24', 'INTERVAL 1 YEAR', ROUND_DOWN) "result" FROM DUMMY;
SELECT SERIES_ROUND('04:25:01', 'INTERVAL 10 MINUTE') "result" FROM DUMMY;
The SERIES_ROUND from SAP Hana provides similar functionalities as DATE_TRUNC in other vendors.
https://help.sap.com/docs/SAP_HANA_PLATFORM/4fe29514fd584807ac9f2a04f6754767/435ec476ab494ad6b8409f22abec13fe.html?version=2.0.00
Converting to a non-datetime data type is usually not a good idea (additional parsing, encoding, semantics...).
Instead use a less granular datetime data type: daydate in this case.
create column table datatab (start_time seconddate, bus_id int, distance_two_points decimal (10, 2));
insert into datatab values (to_seconddate('05.09.2015 13:12:00'), 1, 50.2);
insert into datatab values (to_seconddate('05.09.2015 13:22:00'), 1, 1.2);
insert into datatab values (to_seconddate('05.09.2015 15:32:00'), 1, 24);
insert into datatab values (to_seconddate('05.09.2015 13:12:00'), 1, 50.2);
insert into datatab values (to_seconddate('05.09.2015 14:22:00'), 2, 1.2);
insert into datatab values (to_seconddate('05.09.2015 16:32:00'), 2, 24);
select to_seconddate(day) as day,count(*) as bus_count from(
SELECT to_date(start_time) as day, bus_id, sum(distance_two_points) as distance
FROM datatab
where start_time between '2015-09-05 00:00:00' and '2015-09-05 23:59:59'
group by to_date(start_time),bus_id
) as A
where distance<=250000
group by day;
The inner query gives you:
DAY BUS_ID DISTANCE
2015-09-05 1 75.40
2015-09-05 2 25.20
So, your seconddate "start_time" is now aggregated as daydate and then converted back to 'seconddate'.
What I prefer is using the seconds_between() or nano100_between() function.
select now(),
add_seconds( to_date('1970.01.01', 'YYYY.MM.DD'),
round(
SECONDS_BETWEEN(
to_date('1970.01.01', 'YYYY.MM.DD'),
now()
)/3600
)*3600
)
from dummy;
This looks a bit ugly but given the to_date() is calculated just once and not for each row and the seconds arithmetic is close to how Hana stores the value internally, it should be the most efficient of the lot.
Also it is the most flexible, round by second, minute, hour, day,... everything below year is fine.
PS: round() supports all round and truncate options.
Assuming your start_time is of some data/time type (e.g. SECONDDATE) you could use
...TO_NVARCHAR(START_TIME, 'YYYY-MM-DD') AS DAY...
Instead of date_trunc... in PostgreSQL
Why don't you use CAST() conversion function?
select
cast( now() as date ) myDate
from dummy;
I am trying to use the IIF statements in SS-2012
I have this which works fine
SELECT
NULLIF(IIF( a.EndDate is null
, DATEDIFF(MONTH, a.StartDate, getdate()) ,
IIF( a.EndDate is not null
, DATEDIFF(MONTH, a.StartDate, a.EndDate) , '')),'')
AS Months
,NULLIF(IIF( a.EndDate is null
, DATEDIFF(Day, a.StartDate, getdate()) ,
IIF( a.EndDate is not null
, DATEDIFF(Day, a.StartDate, a.EndDate) , '')),'')
AS DateDays
FROM
TableDates a
The problem I came across is if the start date and enddate are on the same date(I am trying to default it to 1 month and 30 or 31 days whatever month it is)
I am gettiing
int is incompatible with date
When trying this below
,NULLIF(
IIF ( (a.EndDate is null) , DATEDIFF(Day, a.StartDate, getdate()) ,
IIF ( (a.StartDate = a.EndDate)
, DATEADD(Day, DATEDIFF(Day, a.StartDate, a.EndDate), a.EndDate),
IIF ( (a.EndDate is not null) , DATEDIFF(Day, a.StartDate, a.EndDate),'')
)),'')
How can I default the days to 30-31 and month to 1 if the dates are the same?
If you need to show the number of days of the month as default where start date and enddate are on the same date then i hope the below query will work for you
IIF ( (a.StartDate = a.EndDate),
(datediff(day, a.StartDate, dateadd(month, 1, a.StartDate))),...
and to show the month as default where start date and enddate are on the same date
IIF ( (a.StartDate = a.EndDate),Month(a.StartDate),...
I would like to contribute my codes related to the date conversion between local time and UTC time for both current and historical dates, including day light savings time consideration. I reviewed some recent postings but could not find the solution I am looking for so I summarize the solutions I found to develop my own solution. I am running my codes in SQL Server 2008R2. Test cases are provided as comments before each function. Feel free to check out the Credits section for related postings, try out my codes, and let me know if I miss anything. Thanks.
-- Test 1: select dbo.fn_isDayLightSavings(CAST('2014-01-01' AS DATE)), expect 0
-- Test 2: select dbo.fn_isDayLightSavings(CAST('2014-04-14' AS DATE)), expect 1
IF OBJECT_ID(N'fn_isDayLightSavings') IS NOT NULL AND OBJECTPROPERTY(OBJECT_ID(N'fn_isDayLightSavings'),'IsScalarFunction') = 1
DROP FUNCTION fn_isDayLightSavings;
GO
CREATE FUNCTION fn_isDayLightSavings (#dt AS DATETIME)
RETURNS TINYINT
AS
BEGIN
DECLARE #rtn TINYINT, #year INT, #dtsStartMonth DATETIME, #dtsEndMonth DATETIME, #dstStart DATETIME, #dstEnd DATETIME;
SET #year = DATEPART(YEAR, #dt);
-- In year 2007, US day light savings period changes from Apr-Oct to Mar-Nov.
if #year < 2007
BEGIN
-- Last Sunday of April at 2 AM
SET #dtsStartMonth = DATEADD(MONTH, 4, DATEADD(YEAR, #year - 1900, 0));
SET #dstStart = DATEADD(HOUR, 2, DATEADD(day, -(DATEPART(dw, #dtsStartMonth) - 1), #dtsStartMonth));
-- Last Sunday of October at 2 AM
SET #dtsEndMonth = DATEADD(MONTH, 10, DATEADD(YEAR, #year - 1900, 0));
SET #dstEnd = DATEADD(HOUR, 2, DATEADD(day, -(DATEPART(dw, #dtsEndMonth) - 1), #dtsEndMonth));
END
else
BEGIN
-- 2nd Sunday of March at 2 AM
SET #dtsStartMonth = DATEADD(MONTH, 2, DATEADD(YEAR, #year - 1900, 0));
SET #dstStart = DATEADD(HOUR, 2, DATEADD(day, ((15 - DATEPART(dw, #dtsStartMonth)) % 7) + 7, #dtsStartMonth));
-- 1st Sunday of November at 2 AM
SET #dtsEndMonth = DATEADD(MONTH, 10, DATEADD(YEAR, #year - 1900, 0));
SET #dstEnd = DATEADD(HOUR, 2, DATEADD(day, ((8 - DATEPART(dw, #dtsEndMonth)) % 7) + 7, #dtsEndMonth));
END
if #dt BETWEEN #dstStart AND #dstEnd SET #rtn=1 ELSE SET #rtn=0;
RETURN #rtn;
END
GO
-- Test 1: select dbo.fn_DateTime2UTC(CAST('2014-01-01 01:00:00' AS DATETIME), 0), expect '2014-01-01 07:00:00.000'
-- Test 2: select dbo.fn_DateTime2UTC(CAST('2014-01-01 01:00:00' AS DATETIME), 1), expect '2013-01-01 07:00:00.000'
-- Test 3: select dbo.fn_DateTime2UTC(CAST('2014-05-01 01:00:00' AS DATETIME), 0), expect '2014-05-01 06:00:00.000'
-- Test 4: select dbo.fn_DateTime2UTC(CAST('2014-05-01 01:00:00' AS DATETIME), 1), expect '2014-05-01 07:00:00.000'
IF OBJECT_ID(N'fn_DateTime2UTC') IS NOT NULL AND OBJECTPROPERTY(OBJECT_ID(N'fn_DateTime2UTC'),'IsScalarFunction') = 1
DROP FUNCTION fn_DateTime2UTC;
GO
CREATE FUNCTION fn_DateTime2UTC (#dt AS DATETIME, #ignoreDST AS TINYINT = 0)
-- do CAST(? AS DATETIMEOFFSET), if need datetimeoffset type
RETURNS DATETIME
AS
BEGIN
DECLARE #tzOffset INT, #utcDt DATETIME;
-- Get current time zone offset in minutes
SET #tzOffset = DATEPART(TZoffset, SYSDATETIMEOFFSET()) +
(CASE WHEN dbo.fn_isDayLightSavings(#dt)=1 THEN 60 ELSE 0 END);
if dbo.fn_isDayLightSavings(#dt)=0
set #utcDt = DATEADD(MINUTE, -#tzOffset, #dt);
else if #ignoreDST=0
set #utcDt = DATEADD(MINUTE, -#tzOffset, #dt);
else
set #utcDt = DATEADD(MINUTE, -#tzOffset+60, #dt);
return #utcDt;
END
GO
-- Test 1: select dbo.fn_UTC2DateTime(CAST('2014-01-01 07:00:00.000' AS DATETIME), 0), expect '2014-01-01 01:00:00'
-- Test 2: select dbo.fn_UTC2DateTime(CAST('2013-01-01 07:00:00.000' AS DATETIME), 1), expect '2014-01-01 01:00:00'
-- Test 3: select dbo.fn_UTC2DateTime(CAST('2014-05-01 06:00:00.000' AS DATETIME), 0), expect '2014-05-01 01:00:00'
-- Test 4: select dbo.fn_UTC2DateTime(CAST('2014-05-01 07:00:00.000' AS DATETIME), 1), expect '2014-05-01 01:00:00'
IF OBJECT_ID(N'fn_UTC2DateTime') IS NOT NULL AND OBJECTPROPERTY(OBJECT_ID(N'fn_UTC2DateTime'),'IsScalarFunction') = 1
DROP FUNCTION fn_UTC2DateTime;
GO
CREATE FUNCTION fn_UTC2DateTime (#utcDt AS DATETIME, #ignoreDST AS TINYINT = 0)
RETURNS DATETIME
AS
BEGIN
DECLARE #tzOffset INT, #dt DATETIME;
-- Get current time zone offset in minutes
SET #tzOffset = DATEPART(TZoffset, SYSDATETIMEOFFSET()) +
(CASE WHEN dbo.fn_isDayLightSavings(#utcDt)=1 THEN 60 ELSE 0 END);
if dbo.fn_isDayLightSavings(#utcDt)=0
set #dt = DATEADD(MINUTE, #tzOffset, #utcDt);
else if #ignoreDST=0
set #dt = DATEADD(MINUTE, #tzOffset, #utcDt);
else
set #dt = DATEADD(MINUTE, #tzOffset-60, #utcDt);
return #dt;
END
GO
-- Test 1: select dbo.fn_UTC2DateTimeOffset(CAST('2014-01-01 07:00:00.000' AS DATETIME), 0), expect '2014-01-01 01:00:00.0000000 -06:00'
-- Test 2: select dbo.fn_UTC2DateTimeOffset(CAST('2013-01-01 07:00:00.000' AS DATETIME), 1), expect '2014-01-01 01:00:00.0000000 -06:00'
-- Test 3: select dbo.fn_UTC2DateTimeOffset(CAST('2014-05-01 06:00:00.000' AS DATETIME), 0), expect '2014-05-01 01:00:00.0000000 -05:00'
-- Test 4: select dbo.fn_UTC2DateTimeOffset(CAST('2014-05-01 07:00:00.000' AS DATETIME), 1), expect '2014-05-01 00:00:00.0000000 -06:00'
IF OBJECT_ID(N'fn_UTC2DateTimeOffset') IS NOT NULL AND OBJECTPROPERTY(OBJECT_ID(N'fn_UTC2DateTimeOffset'),'IsScalarFunction') = 1
DROP FUNCTION fn_UTC2DateTimeOffset;
GO
CREATE FUNCTION fn_UTC2DateTimeOffset (#utcDt AS DATETIME, #ignoreDST TINYINT = 0)
RETURNS DATETIMEOFFSET
AS
BEGIN
DECLARE #tzOffset INT, #dt DATETIMEOFFSET;
-- Get current time zone offset in minutes
SET #tzOffset = DATEPART(TZoffset, SYSDATETIMEOFFSET()) +
(CASE WHEN dbo.fn_isDayLightSavings(#utcDt)=1 THEN 60 ELSE 0 END);
if dbo.fn_isDayLightSavings(#utcDt)=0
set #dt = SWITCHOFFSET(CAST(#utcDt AS DATETIMEOFFSET), #tzOffset);
else if #ignoreDST=0
set #dt = SWITCHOFFSET(CAST(#utcDt AS DATETIMEOFFSET), #tzOffset);
else
set #dt = SWITCHOFFSET(CAST(#utcDt AS DATETIMEOFFSET), #tzOffset-60);
return #dt;
END
GO
-- Credits:
-- Determination of day light savings start and end time, Jamie F., 11/1/2013
-- (http://stackoverflow.com/questions/19732896/how-to-create-daylight-savings-time-start-and-end-function-in-sql-server)
-- Day light savings time calendar, USNO
-- (http://aa.usno.navy.mil/faq/docs/daylight_time.php)
-- Time zone offset, Microsoft
-- (http://msdn.microsoft.com/en-us/library/ms174420.aspx)
-- Local system date time with time zone, Robert Cantor, 12/7/2013
-- (http://stackoverflow.com/questions/1205142/tsql-how-to-convert-local-time-to-utc-sqlserver2008)
-- Convert date with time zone and day light savings, Eric Z Beard, 8/24/2008
-- (http://stackoverflow.com/questions/24797/effectively-converting-dates-between-utc-and-local-ie-pst-time-in-sql-2005#25073)
Kudos to you for assembling that knowledge into one place. Assuming it is accurate, it's easy to pick up and use immediately.
However, the trouble is that without an extensive set of unit tests you can't be sure of accuracy.
Might I suggest the best option for date/time conversions would be to use an existing highly tested open source library such as http://nodatime.org/. Date/time conversions have so many intracacies and details that could not possibly be contained in a few dozen lines of SQL code.
nodatime is a .NET library that should easily be accessible via the SQL Server CLR user-defined functions feature.