Manipulating timestamps without converting them to datetime in MySql 8 - datetime

It seems MySql 8 differenciates TIMESTAMP from DATETIME more than previous versions (at least more than 5.7) and java drivers understand a Timestamp is universal (senconds since epoch) while DATETIME is like a textual representation of date and time without timezone information, it is not an instant in time.
I need to work with timestamps but I need to add 1 second to one of them in a SELECT query. Unfortunately I can't do it. If I try to do it then it gets converted to DATETIME with it's side effects, as they are not the same.
This code can be using for testing without other programming language:
CREATE TABLE z (
`id` bigint unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
`myTs` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB;
insert into z (myTs) values (TIMESTAMP'2023-01-01 00:00:00+00:00');
create table x as select myTs + interval 1 second from z limit 1;
desc x;
drop table x;
drop table z;
You will get myTs + interval 1 second | datetime | ...
But if you remove + interval 1 second then you get myTs | timestamp | ...
I have read the documentation and tried different functions and I couldn't avoid or reverse this conversion.
Specifically I tried at least timestamp(myTs + interval 1 second), timestampadd(second, 1, myTs), date_add(myTs, interval 1 second) and timestamp(myTs + 1).
I need to either sum 1 second to a timestamp without it being converted to datetime or a way to convert a datetime to a timestamp type (providing a time zone if needed) in MySql 8.
I'm using MySql 8.0.30.
Thank you.

Related

Datetime column from Table1 is not matching the DateTime column from Table 2

Hello I have an issue of matching two different datetime columns.
I need to compare the two of them (and their data), but at the moment of putting them in the same table (using a datetime relation) I do not get the match I need:
What I need:
| Datetime_1 | Datetime_2 |
| ---------- | ---------- |
| 01/01/2023 08:00:00 AM | |
... ...
| 01/11/2023 12:00:00 AM | 01/11/2023 12:00:00 AM |
| 01/11/2023 01:00:00 AM | 01/11/2023 01:00:00 AM |
... ...
| 31/01/2023 12:00:00 PM | 31/01/2023 12:00:00 PM |
What I get:
Datetime_1 goes from 01/01/2023 12:00:00AM to 01/31/2023 11:00:00PM (with steps of 1h) and Datetime_2 goes from 01/11/2023 8:15:00 PM to 02/06/2023 7:45:00 PM (with steps of 30min).
I did a relation with the two of them and I didn't receive any error:
I already put both lists in Date/Time format in Power Query and Data panel.
However, I noticed my main datetime list doesn't have the hierarchy icon on fields panel, while the secondary datetime lists have it, (but not the hour section):
Also, as I mentioned before, my list have a range between Jan and Feb. I do not understand why this range continues and match some dates on the on my main datetime list:
Troubleshooting
Part of the difficulty troubleshooting this is the two columns are formatted differently. Just for now, make sure both are formatted as Long Date Time. When comparing the relationship, do not drag the hierarchy (for the one that has it) into the table but rather just the date itself. When you do, you will see the full timestamp for both columns and the issue will become more clear.
Power BI & Relationships on DateTime
Power BI will only match related rows if the date and time match exactly, so 4/15/2023 12:00:00 AM will not match 4/15/2023/12:00:01 AM. You mentioned one side of the relationship has 30 minute steps while the other has 1 hour steps. Power BI is not going to match up a 1:30am and 1:00am value for you. If you want that 1:30 value to match up to 1:00, create another column truncating the :30 minutes and build your relationship on the truncated column.
Time Dimension
I'm not sure of your application so don't know if this will work, but when dealing with time, I try to separate Date and Time into separate columns and have both a Date and Time dimension. Below is my time dimension DAX. You can generate any minute-precise interval with it. Notice the last defined column "timekey". I create a column in my fact table to relate to this key.
DimTime =
var every_n_minutes = 15 /* between 0 and 60; remainders in last hourly slice */
/* DO NOT CHANGE BELOW THIS LINE */
var slice_per_hour = trunc(DIVIDE(60,every_n_minutes),0)
var rtn =
ADDCOLUMNS(
SELECTCOLUMNS(
GENERATESERIES(0, 24*slice_per_hour - 1, 1),
"hour24", TRUNC(DIVIDE([Value],slice_per_hour),0),
"mins", MOD([Value],slice_per_hour) * every_n_minutes
),
"hour12", MOD([hour24] + 11,12) + 1,
"asTime", TIME([hour24],[mins],0),
"timekey", [hour24] * 100 + [mins]
)
return rtn
As requested, turning this into an answer. The reason you're getting these results is that your time stamps will never line up. Yes, it let you create the join, but my guess is that is only because both fields have the same formatting. Also, it is best practices to separate your dates and time in separate date and time dimensions, then join them via a fact table. See also here.

Informix FROM_UNIXTIME alternative

I was searching for a way to group data by interval (ex: every 30 minutes) using the date defined in that table, so i need to convert that date time to milliseconds so that i can divide it by the interval i need like in this query
SELECT FLOOR(UNIX_TIMESTAMP(timestamp)/(15 * 60 * 1000)) AS timekey
FROM table
GROUP BY timekey;
This query is running perfectly on SQL Server but on informix it's giving me the error
Routine (unix_timestamp) can not be resolved.
As it's not defined in IBM Informix server.
So i need a direct way to get epoch unix time from timestamp DATETIME YEAR TO FRACTION(3) column in IBM informix server like 'UNIX_TIMESTAMP' in SQL server.
If the timestamp column is of type DATETIME YEAR TO SECOND or similar, then you can convert it to a DECIMAL(18,5) number of seconds since the Unix Epoch, aka 1970-01-01 00:00:00Z (UTC; time zone offset +00:00) using a procedure such as this:
{
# "#(#)$Id: tounixtime.spl,v 1.6 2002/09/25 18:10:48 jleffler Exp $"
#
# Stored procedure TO_UNIX_TIME written by Jonathan Leffler (previously
# jleffler#informix.com and now jleffler#us.ibm.com). Includes fix for
# bug reported by Tsutomu Ogiwara <Tsutomu.Ogiwara#ctc-g.co.jp> on
# 2001-07-13. Previous version used DATETIME(0) SECOND TO SECOND
# instead of DATETIME(0:0:0) HOUR TO SECOND, and when the calculation
# extended the shorter constant to DATETIME HOUR TO SECOND, it added the
# current hour and minute fields, as documented in the Informix Guide to
# SQL: Syntax manual under EXTEND in the section on 'Expression'.
# Amended 2002-08-23 to handle 'eternity' and annotated more thoroughly.
# Amended 2002-09-25 to handle fractional seconds, as companion to the
# new stored procedure FROM_UNIX_TIME().
#
# If you run this procedure with no arguments (use the default), you
# need to worry about the time zone the database server is using because
# the value of CURRENT is determined by that, and you need to compensate
# for it if you are using a different time zone.
#
# Note that this version works for dates after 2001-09-09 when the
# interval between 1970-01-01 00:00:00+00:00 and current exceeds the
# range of INTERVAL SECOND(9) TO SECOND. Returning DECIMAL(18,5) allows
# it to work for all valid datetime values including fractional seconds.
# In the UTC time zone, the 'Unix time' of 9999-12-31 23:59:59 is
# 253402300799 (12 digits); the equivalent for 0001-01-01 00:00:00 is
# -62135596800 (11 digits). Both these values are unrepresentable in
# 32-bit integers, of course, so most Unix systems won't handle this
# range, and the so-called 'Proleptic Gregorian Calendar' used to
# calculate the dates ignores locale-dependent details such as the loss
# of days that occurred during the switch between the Julian and
# Gregorian calendar, but those are minutiae that most people can ignore
# most of the time.
}
CREATE PROCEDURE to_unix_time(d DATETIME YEAR TO FRACTION(5)
DEFAULT CURRENT YEAR TO FRACTION(5))
RETURNING DECIMAL(18,5);
DEFINE n DECIMAL(18,5);
DEFINE i1 INTERVAL DAY(9) TO DAY;
DEFINE i2 INTERVAL SECOND(6) TO FRACTION(5);
DEFINE s1 CHAR(15);
DEFINE s2 CHAR(15);
LET i1 = EXTEND(d, YEAR TO DAY) - DATETIME(1970-01-01) YEAR TO DAY;
LET s1 = i1;
LET i2 = EXTEND(d, HOUR TO FRACTION(5)) -
DATETIME(00:00:00.00000) HOUR TO FRACTION(5);
LET s2 = i2;
LET n = s1 * (24 * 60 * 60) + s2;
RETURN n;
END PROCEDURE;
Some of the commentary about email addresses is no longer valid – things have changed in the decade and a half since I wrote this.

How to cast a column into decimal of varying significant digits in Oracle

I have a column that is stored in ###0.0000000000 format. In a report I'm generating I need it to only show a few significant digits. Problem is the number needed changes based on the product with a default of 2. There's a column in another table that provides the required digits per each product.
I've tried a few things so far but it seems to not like it and throws a syntax error.
Cast(A.Price as Numeric(10,coalesce(B.Sig_Digits,2)))
That threw an error so I tried making the coalesce part a column and aliasing it in case the coalesce broke it, and that didn't work either. Round will take a column as an argument but I don't want it to round. Other than an ugly
case when Sig_digits = 1 then to_char(price,'###0.0') when Sig_digits = 2...
etc. what other options are there? This is a very large report, with 100+ columns and a few million rows so I'd prefer to not do the case when.
Use TO_CHAR with RPAD to add 0s to the end of the format model to the correct number of decimal places:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE table_name ( value, sig ) AS
SELECT 123.456789, 2 FROM DUAL UNION ALL
SELECT 123456789.123456789, 7 FROM DUAL;
Query 1:
SELECT TO_CHAR( value, RPAD( 'FM999999999990.', sig + 15, '0' ) )
FROM table_name
Results:
| TO_CHAR(VALUE,RPAD('FM999999999990.',SIG+15,'0')) |
|---------------------------------------------------|
| 123.46 |
| 123456789.1234568 |

Date Function in Teradata

Is there a function in Teradata, that "makes" a date by giving day, month any year as parameters?
SO if I have integer parameters p1_day, p2_month, and p3_year (which are, by the way, attributes), is there a function like
date_function (p1_day, p2_month, and p3_year) -> for example '2013-12-11'
In TD13.10+ you can create a simple SQL UDF:
-- (year, month, day) to date, "invalid date" error if no valid date
REPLACE FUNCTION ymd_to_date(y INTEGER, m INTEGER, d INTEGER)
RETURNS DATE
SPECIFIC ymd_to_date
RETURNS NULL ON NULL INPUT
CONTAINS SQL
DETERMINISTIC
COLLATION INVOKER
INLINE TYPE 1
RETURN
((y - 1900) * 10000 + (m * 100) + d (DATE))
Dieter
One example in teradata:
BTEQ -- Enter your SQL request or BTEQ command:
sel cast ('11'||'-'||'12'||'-'||'12' as date format 'dd-mm-yy');
sel cast ('11'||'-'||'12'||'-'||'12' as date format 'dd-mm-yy');
*** Query completed. One row found. One column returned.
*** Total elapsed time was 1 second.
(((('11'||'-')||'12')||'-')||'12')
----------------------------------
11-12-12
So you can simply achieve your desired result by following query:
sel cast (cast(p1_day as char(2))||'-'||cast(p2_month as char(2))||'-'||
cast(p3_year as char(2)) as date format 'dd-mm-yy');
P.S. : There doesn't seem any such built-in function in teradata.
As far i as i know there is no predefined date function where you pass the integers and it returns the date.. however you can write you know UDF..
To add to Deiter's function, look at the below queries. Teradata stores dates as Integers with an offset from 1900.
SELECT CAST(CURRENT_DATE AS INTEGER);
---- 1150818
SELECT CURRENT_DATE;
--- 2015-08-18
---- the format of storage is (<year> - 1900)mmdd
SELECT (2015 -1900)*100000 + (8 * 100)+ 18;
------ 1150818
115 years from 1900, month followed by date.

How do I convert an interval into a number of hours with postgres?

Say I have an interval like
4 days 10:00:00
in postgres. How do I convert that to a number of hours (106 in this case?) Is there a function or should I bite the bullet and do something like
extract(days, my_interval) * 24 + extract(hours, my_interval)
Probably the easiest way is:
SELECT EXTRACT(epoch FROM my_interval)/3600
If you want integer i.e. number of days:
SELECT (EXTRACT(epoch FROM (SELECT (NOW() - '2014-08-02 08:10:56')))/86400)::int
To get the number of days the easiest way would be:
SELECT EXTRACT(DAY FROM NOW() - '2014-08-02 08:10:56');
As far as I know it would return the same as:
SELECT (EXTRACT(epoch FROM (SELECT (NOW() - '2014-08-02 08:10:56')))/86400)::int;
select floor((date_part('epoch', order_time - '2016-09-05 00:00:00') / 3600)), count(*)
from od_a_week
group by floor((date_part('epoch', order_time - '2016-09-05 00:00:00') / 3600));
The ::int conversion follows the principle of rounding.
If you want a different result such as rounding down, you can use the corresponding math function such as floor.
If you convert table field:
Define the field so it contains seconds:
CREATE TABLE IF NOT EXISTS test (
...
field INTERVAL SECOND(0)
);
Extract the value. Remember to cast to int other wise you can get an unpleasant surprise once the intervals are big:
EXTRACT(EPOCH FROM field)::int
If you want to display your result only in date type after adding the interval then, should try this
Select (current_date + interval 'x day')::date;
I'm working with PostgreSQL 11, and I created a function to get the hours betweeen 2 differents timestamps
create function analysis.calcHours(datetime1 timestamp, datetime2 timestamp)
returns integer
language plpgsql as $$
declare
diff interval;
begin
diff = datetime2 - datetime1;
return (abs(extract(days from diff))*24 + abs(extract(hours from diff)))::integer;
end; $$;
select date 'now()' - date '1955-12-15';
Here is the simple query which calculates total no of days.

Resources