Issues with timestamp_ltz datatypes - snowflake-cloud-data-platform

Observing a weird issue in Snowflake.
for below table the results for all years before 1884-01-01 00:00:00.000001000 are showing different values
CREATE TABLE time_tester1(time1 TIMESTAMP_LTZ, time2 TIMESTAMP_LTZ)
INSERT INTO time_tester1
values('1884-01-01 00:00:00.000001000','1883-01-01 00:00:00.000001000')
Result
SELECT * FROM time_tester1
Row TIME1 TIME2
1 1884-01-01 00:00:00.000001000 -05:00 1882-12-31 23:56:02.000001000 -05:00
this issue is observed for all years less then 1884

It seems the issue is related with "The Day of Two Noons":
https://dba.stackexchange.com/a/127972
If you use UTC, you will not get this result:
CREATE or replace TABLE time_tester1(time1 TIMESTAMP_LTZ, time2 TIMESTAMP_LTZ);
INSERT INTO time_tester1
values('1884-01-01 00:00:00.000001000','1883-01-01 00:00:00.000001000');
SELECT * FROM time_tester1;
+-------------------------------+-------------------------------+
| TIME1 | TIME2 |
+-------------------------------+-------------------------------+
| 1884-01-01 00:00:00.000 +0000 | 1883-01-01 00:00:00.000 +0000 |
+-------------------------------+-------------------------------+

Related

SNOWFLAKE conversion DATETIME 0

I am aware that Snowflake is very similar to Oracle. I am doing a job that requires me to move some SQL Server code over into snowflake , however I can't seem to get these date functions converted over. In SSMS this SELECT DATEADD(YEAR,DATEDIFF(YEAR,0,'1912-01-01'),0) statement would return 1912-01-01 00:00:000. since the 0 indicates "The beginning of time" what would be Snowflakes equivalent to this 0 be and better yet how would you convert this to say Oracle code?
Thank you ahead of time!
Sharing few examples from Snowflake -
select date_trunc(year,'1912-01-05'::date);
+-------------------------------------+
| DATE_TRUNC(YEAR,'1912-01-05'::DATE) |
|-------------------------------------|
| 1912-01-01 |
+-------------------------------------+
select date_trunc(year,'1912-10-05'::date);
+-------------------------------------+
| DATE_TRUNC(YEAR,'1912-10-05'::DATE) |
|-------------------------------------|
| 1912-01-01 |
+-------------------------------------+
select date_trunc(year,'1912-12-01 10:00:000'::timestamp);
+----------------------------------------------------+
| DATE_TRUNC(YEAR,'1912-12-01 10:00:000'::TIMESTAMP) |
|----------------------------------------------------|
| 1912-01-01 00:00:00.000 |
+----------------------------------------------------+
I am familiar with the method you are talking about. It was a workaround to make up for the fact that SQL Server did not have a function to truncate date/time.
In Snowflake, just use DATE_TRUNC( <date_or_time_part>, <date_or_time_expr> )
https://docs.snowflake.com/en/sql-reference/functions/date_trunc.html
select to_date('2015-05-08T23:39:20.123-07:00') as "DATE1",
date_trunc('YEAR', "DATE1") as "TRUNCATED TO YEAR",
date_trunc('MONTH', "DATE1") as "TRUNCATED TO MONTH",
date_trunc('DAY', "DATE1") as "TRUNCATED TO DAY";
+------------+-------------------+--------------------+------------------+
| DATE1 | TRUNCATED TO YEAR | TRUNCATED TO MONTH | TRUNCATED TO DAY |
|------------+-------------------+--------------------+------------------|
| 2015-05-08 | 2015-01-01 | 2015-05-01 | 2015-05-08 |
+------------+-------------------+--------------------+------------------+
select to_timestamp('2015-05-08T23:39:20.123-07:00') as "TIMESTAMP1",
date_trunc('HOUR', "TIMESTAMP1") as "TRUNCATED TO HOUR",
date_trunc('MINUTE', "TIMESTAMP1") as "TRUNCATED TO MINUTE",
date_trunc('SECOND', "TIMESTAMP1") as "TRUNCATED TO SECOND";
+-------------------------+-------------------------+-------------------------+-------------------------+
| TIMESTAMP1 | TRUNCATED TO HOUR | TRUNCATED TO MINUTE | TRUNCATED TO SECOND |
|-------------------------+-------------------------+-------------------------+-------------------------|
| 2015-05-08 23:39:20.123 | 2015-05-08 23:00:00.000 | 2015-05-08 23:39:00.000 | 2015-05-08 23:39:20.000 |
+-------------------------+-------------------------+-------------------------+-------------------------+
Snowflake and Oracle both have a date truncate function
Snowflake:
DATE_TRUNC has many supported periods it can truncate to:
SELECT '1921-12-23'::date as d
,DATE_TRUNC('year', d) as d_trunc_to_year;
gives:
D
D_TRUNC_TO_YEAR
1921-12-23
1921-01-01
Oracle:
Oracle has TRUNC
Which there example looks to solve a rather similar way:
SELECT TRUNC(TO_DATE('27-OCT-92','DD-MON-YY'), 'YEAR')
"New Year" FROM DUAL;
New Year
---------
01-JAN-92

Force UTC time in Snowflake JOIN condition

I have a setup where we have
A landing table with a column of type TIMESTAMP_LTZ (consumption_date). Includes the timezone of +02:00
A view (landing_view) that reads from the landing table
A view (raw_data) that reads from a table that has a field of type TIMESTAMP_NTZ (SOURCE_TIMESTAMP), but the value itself is in UTC time.
I have to join the data from landing_view to the data from raw_data using the consumption_date and SOURCE_TIMESTAMP.
SELECT l.ID, l.consumption_date, l.RUN_TIME, r.DISPLAY_NAME, r.source_timestamp, r.value_as_double
FROM "raw_data" r
JOIN "landing_view" l
ON r.SOURCE_TIMESTAMP >= DATEADD(second,120, convert_timezone('UTC',l.consumption_date))
and r.SOURCE_TIMESTAMP < DATEADD(second,1000, convert_timezone('UTC',l.consumption_date))
My problem is that the convert_timezone command does not seem to affect the join clause at all, insted the join is made using the local time included in the LTZ type (+02:00).
If I use the convert_timezone is a select, if works just fine, but for the JOIN it does not.
Is there a way I can tell snowflake to use UTC in the join?
This will depend on what your TIMEZONE setting is. See example below.
If TIMEZONE is UTC:
alter session set TIMEZONE = 'UTC';
select
-- 2AM UTC
'2021-01-02 02:00:00'::timestamp_ntz as SOURCE_TIMESTAMP,
-- 1AM UTC / 12PM Australia/Melbourne time / 1 hour before SOURCE_TIMESTAMP
'2021-01-02 12:00:00 +1100'::timestamp_ltz as CONSUMPTION_DATE,
-- so add one hour to CONSUMPTION_DATE should equal to SOURCE_TIMESTAMP
SOURCE_TIMESTAMP = DATEADD(hour, 1, convert_timezone('UTC', CONSUMPTION_DATE)) as is_equal
;
+-------------------------------+-------------------------------+----------+
| SOURCE_TIMESTAMP | CONSUMPTION_DATE | IS_EQUAL |
|-------------------------------+-------------------------------+----------|
| 2021-01-02 02:00:00.000000000 | 2021-01-02 01:00:00.000 +0000 | True |
+-------------------------------+-------------------------------+----------+
However, if you change your TIMEZONE setting to another timezone, the result will be different:
alter session set TIMEZONE = 'Australia/Melbourne';
select
-- 2AM UTC
'2021-01-02 02:00:00'::timestamp_ntz as SOURCE_TIMESTAMP,
-- 1AM UTC / 12PM Australia/Melbourne time / 1 hour before SOURCE_TIMESTAMP
'2021-01-02 12:00:00 +1100'::timestamp_ltz as CONSUMPTION_DATE,
-- so add one hour to CONSUMPTION_DATE should equal to SOURCE_TIMESTAMP
SOURCE_TIMESTAMP = DATEADD(hour, 1, convert_timezone('UTC', CONSUMPTION_DATE)) as is_equal
;
+-------------------------------+-------------------------------+----------+
| SOURCE_TIMESTAMP | CONSUMPTION_DATE | IS_EQUAL |
|-------------------------------+-------------------------------+----------|
| 2021-01-02 02:00:00.000000000 | 2021-01-02 12:00:00.000 +1100 | False |
+-------------------------------+-------------------------------+----------+
Since you SOURCE_TIMESTAMP stores UTC value, you should change your TIMEZONE setting to match it.
By the way, having CONVERT_TIMEZONE in the DATEADD is redundant, as it only adds extra operation, but not having any effects. See below example:
select
-- 1AM UTC / 9AM Australia/Perth time / 1 hour before SOURCE_TIMESTAMP
'2021-01-02 09:00:00 +0800'::timestamp_ltz as CONSUMPTION_DATE,
DATEADD(hour, 1, CONSUMPTION_DATE) as no_convert_tz,
DATEADD(hour, 1, convert_timezone('UTC', CONSUMPTION_DATE)) as convert_tz,
no_convert_tz = convert_tz
;
+-------------------------------+-------------------------------+-------------------------------+----------------------------+
| CONSUMPTION_DATE | NO_CONVERT_TZ | CONVERT_TZ | NO_CONVERT_TZ = CONVERT_TZ |
|-------------------------------+-------------------------------+-------------------------------+----------------------------|
| 2021-01-02 12:00:00.000 +1100 | 2021-01-02 13:00:00.000 +1100 | 2021-01-02 02:00:00.000 +0000 | True |
+-------------------------------+-------------------------------+-------------------------------+----------------------------+
You can see that the last column returns True.

How to calculate time duration in sql server 2014? [duplicate]

This question already has an answer here:
I want to calculate time diff between starttime=23:30 and endtime=00:15 the time diff is coming -23.25
(1 answer)
Closed 5 years ago.
This is My First Condition. suppose CheckIn Time is Greater Than Check Out Time so How Can I calculate Time Duration
StaffName | attendDate| staffid| firmId| Shiftname | AttendId| CheckIn| CheckOut | Total Duration
---------------------------------------------------------------------------------------------
Kiran A Veri | 2017-03-28 |5146 |1 | Night | 34584 |18:00:00| 03:00:00 | 09:00:00
This is my second condition. If check in time is less than checkout time so how to manage both condition in this Query?
StaffName | attendDate| staffid| firmId| Shiftname | AttendId| CheckIn| CheckOut | Total Duration
---------------------------------------------------------------------------------------------
Ritesh B Patel | 2017-03-28 |5146 |1 | General | 34584 |10:06:06| 19:35:46 | 09:29:00
For the first part:
Use a CASE WHEN CheckIn > CheckOut in conjunction with DATEDIFF.
For the second part:
Build a datetime or time field and convert it using Style=108 (hh.mm.ss)
CREATE TABLE TEST(ID int, CheckIn time, CheckOut time);
INSERT INTO TEST VALUES(1, '03:00:00', '10:00:00'),(2, '10:26:13', '03:12:15'),(3, '18:00:00', '03:00:00');
-- Below SQL-Server 2012
SELECT CASE WHEN CheckIn > CheckOut
THEN CONVERT(VARCHAR(20), 86400 - DATEADD(SECOND, DATEDIFF(SECOND, CheckOut, CheckIn), '00:00:00'), 108)
ELSE CONVERT(VARCHAR(20),DATEADD(SECOND, DATEDIFF(SECOND, CheckIn, CheckOut), '00:00:00'), 108)
END Elapsed_Time
FROM TEST
-- SQL-Server 2012 or above
SELECT CASE WHEN CheckIn > CheckOut
THEN FORMAT(86400 - DATEADD(SECOND, DATEDIFF(SECOND, CheckOut, CheckIn), '00:00:00'), 'hh\:mm\:ss')
ELSE FORMAT(DATEADD(SECOND, DATEDIFF(SECOND, CheckIn, CheckOut), '00:00:00'), 'hh\:mm\:ss')
END Elapsed_Time
FROM TEST
GO
| Elapsed_Time |
| :----------- |
| 07:00:00 |
| 16:46:02 |
| 09:00:00 |
| Elapsed_Time |
| :----------- |
| 07:00:00 |
| 04:46:02 |
| 09:00:00 |
dbfiddle here

Using SQL Server windowing function to get running total by fiscal year

I'm using SQL Server 2014. I have a Claims table containing totals of claims made per month in my system:
+-----------+-------------+------------+
| Claim_ID | Claim_Date | Nett_Total |
+-----------+-------------+------------+
| 1 | 31 Jan 2012 | 321454.67 |
| 2 | 29 Feb 2012 | 523542.34 |
| 3 | 31 Mar 2012 | 35344.33 |
| 4 | 30 Apr 2012 | 142355.63 |
| etc. | etc. | etc. |
+-----------+-------------+------------+
For a report I am writing I need to be able to produce a cumulative running total that resets to zero at the start of each fiscal year (in my country this is from March 1 to February 28/29 of the following year).
The report will look similar to the table, with an extra running total column, something like:
+-----------+-------------+------------+---------------+
| Claim_ID | Claim_Date | Nett_Total | Running Total |
+-----------+-------------+------------+---------------+
| 1 | 31 Jan 2012 | 321454.67 | 321454.67 |
| 2 | 29 Feb 2012 | 523542.34 | 844997.01 |
| 3 | 31 Mar 2012 | 35344.33 | 35344.33 | (restart at 0
| 4 | 30 Apr 2012 | 142355.63 | 177699.96 | for new yr)
| etc. | etc. | etc. | |
+-----------+-------------+------------+---------------+
I know windowing functions are very powerful and I've used them in rudimentary ways in the past to get overall sums and averages while avoiding needing to group my resultset rows. I have an intuition that I will need to employ the 'preceding' keyword to get the running total for the current fiscal year each row falls into, but I can't quite grasp how to express the fiscal year as a concept to use in the 'preceding' clause (or if indeed it's possible to use a date range in this way).
Any assistance on the way of "phrasing" the fiscal year for the "preceding" clause will be of enormous help to me, please.
i think you should try this:
/* Create Table*/
CREATE TABLE dbo.Claims (
Claim_ID int
,Claim_Date datetime
,Nett_Total decimal(10,2)
);
/* Insert Testrows*/
INSERT INTO dbo.Claims VALUES
(1, '20120101', 10000)
,(2, '20120202', 10000)
,(3, '20120303', 10000)
,(4, '20120404', 10000)
,(5, '20120505', 10000)
,(6, '20120606', 10000)
,(7, '20120707', 10000)
,(8, '20120808', 10000)
Query the Data:
SELECT Claim_ID, Claim_Date, Nett_Total, SUM(Nett_Total) OVER
(PARTITION BY YEAR(DATEADD(month,-2,Claim_Date)) ORDER BY Claim_ID) AS
[Running Total] FROM dbo.Claims
The Trick: PARTITION BY YEAR(DATEADD(month,-2,Claim_Date))
New Partition by year, but i change the date so it fits your fiscal year.
Output:
Claim_ID |Claim_Date |Nett_Total |Running Total
---------+---------------------------+------------+-------------
1 |2012-01-01 00:00:00.000 |10000.00 |10000.00
2 |2012-02-02 00:00:00.000 |10000.00 |20000.00
3 |2012-03-03 00:00:00.000 |10000.00 |10000.00 <- New partition
4 |2012-04-04 00:00:00.000 |10000.00 |20000.00
5 |2012-05-05 00:00:00.000 |10000.00 |30000.00
6 |2012-06-06 00:00:00.000 |10000.00 |40000.00
7 |2012-07-07 00:00:00.000 |10000.00 |50000.00
8 |2012-08-08 00:00:00.000 |10000.00 |60000.00

Cassandra CQL token function for pagination

I am new to CQL and trying to add pagination support for my tables defined in cassandra as shown below -
cqlsh:dev> create table emp4 (empid uuid , year varchar , month varchar , day varchar, primary key((year, month, day), empid));
cqlsh:dev> insert into emp4 (empid, year, month, day) values (08f823ac-4dd2-11e5-8ad6-0c4de9ac7563,'2014','03','19');
cqlsh:dev> insert into emp4 (empid, year, month, day) values (08f823ac-4dd2-11e5-8ad6-0c4de9ac7562,'2016','03','19');
cqlsh:dev> select * from emp4;
year | month | day | empid
------+-------+-----+--------------------------------------
2016 | 03 | 19 | 08f823ac-4dd2-11e5-8ad6-0c4de9ac7562
2015 | 03 | 19 | 08f823ac-4dd2-11e5-8ad6-0c4de9ac756f
2014 | 03 | 19 | 08f823ac-4dd2-11e5-8ad6-0c4de9ac7563
When I try to execute a query to fetch the records based on the the following comparison, the statement seems to be incomplete as show below -
cqlsh:dev> select * from emp4 where token(year, month, day, empid) > token('2014','04',28',08f823ac-4dd2-11e5-8ad6-0c4de9ac7563) LIMIT 1;
... ;
...
I am trying to fetch records which have year,month, day greater than a specific value and also a given uuid. I think I am executing the query in the wrong way. Can someone help me with this ?
First of all, inputs that you send to the token() function must match your partition key...not your complete primary key:
Secondly, the order of your partition values is not necessarily the same as the tokens generated for them. Look what happens when I insert three more rows, and the query using the token function:
system.token(year, month, day) | year | month | day | empid
--------------------------------+------+-------+-----+--------------------------------------
-8209483605981607433 | 2016 | 03 | 19 | 08f823ac-4dd2-11e5-8ad6-0c4de9ac7562
-6378102587642519893 | 2015 | 03 | 19 | 08f823ac-4dd2-11e5-8ad6-0c4de9ac7562
-5253110411337677325 | 2013 | 03 | 19 | 08f823ac-4dd2-11e5-8ad6-0c4de9ac7562
-3665221797724106443 | 2011 | 03 | 19 | 08f823ac-4dd2-11e5-8ad6-0c4de9ac7562
-2421035798234525153 | 2012 | 03 | 19 | 08f823ac-4dd2-11e5-8ad6-0c4de9ac7562
-742508345287024993 | 2014 | 03 | 19 | 08f823ac-4dd2-11e5-8ad6-0c4de9ac7563
(6 rows)
As you can see, the rows are decidedly not in order by year. And in this case your 2014 row has generated the largest token. Therefore querying for rows with a token value larger than that year will yield nothing. But, if I want to query for rows with a token year greater than 2013, it works:
SELECT token(year,month,day),year,month,day,empid FROM emp4
WHERE token(year,month,day) > token('2013','03','19');
system.token(year, month, day) | year | month | day | empid
--------------------------------+------+-------+-----+--------------------------------------
-3665221797724106443 | 2011 | 03 | 19 | 08f823ac-4dd2-11e5-8ad6-0c4de9ac7562
-2421035798234525153 | 2012 | 03 | 19 | 08f823ac-4dd2-11e5-8ad6-0c4de9ac7562
-742508345287024993 | 2014 | 03 | 19 | 08f823ac-4dd2-11e5-8ad6-0c4de9ac7563
(3 rows)
Also note that you will need to use dates of your existing rows to return results that are of more value to you. After all, the token generated by token('2014','04','28') may not actually be greater than the token generated by token('2014','03','19').

Resources