SQL compilation error: Expression type does not match column data type, expecting TIMESTAMP_NTZ(9) but got TIMESTAMP_LTZ(9) for column CREATE_DT - create-table

THE QUESTION: WHAT IS THE PROPER DDL TO USE FOR CREATE TABLE...DEFAULT...CURRENT_TIMESTAMP()
I have a CREATE or REPLACE statement that uses a DEFAULT for the CREATE_DT column- when someone inserts data into the table, the current server date/time should populate the column
CREATE OR REPLACE TABLE "EDW_ADMIN"."ETL_SPROC_LOG" (
"ETL_SPROC_LOG_ID" NUMBER IDENTITY NOT NULL,
"OBJECT_NAME" VARCHAR2(250 CHAR) NOT NULL,
"LOG_ENTRY" VARCHAR2(1000 CHAR) NOT NULL,
"DYNAMIC_SQL" VARCHAR2(10000 CHAR) NULL,
"DURATION" NUMBER NULL,
"ROWS_AFFECTED" NUMBER NULL,
"ERROR_CODE" VARCHAR2(200 CHAR) NULL,
"ERROR_DESC" VARCHAR2(4000 CHAR) NULL,
"CREATE_DT" TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
"CREATE_USER" VARCHAR2(50) NOT NULL DEFAULT CURRENT_USER()
);
When we retrieve data from the column, we would use the following to change the system date/time to our timezone.
ALTER SESSION SET TIMEZONE = 'AMERICA/NEW_YORK';
When we execute a sample insert statement like this one we get an error:
INSERT INTO edw_admin.ETL_SPROC_LOG (OBJECT_NAME, LOG_ENTRY) VALUES ('OBJ', 'ENTRY1');
SQL compilation error: Expression type does not match column data type, expecting TIMESTAMP_NTZ(9) but got TIMESTAMP_LTZ(9) for column CREATE_DT
What is the proper DDL to use for defining the DEFAULT CURRENT_TIMESTAMP()? Do we need to alter the session in the DDL Script prior to the create statement setting the Time Zone to NTZ(9)? I would think Snowflake has multiple servers in different timezones and therefore the System Time would be dependent on where the server is.
The Snowflake Documentation says
Returns the current timestamp for the system.
https://docs.snowflake.net/manuals/sql-reference/functions/current_timestamp.html
It has no arguments to control the Timezone that it returns.
This page in the Snowflake Documentation alludes to the use of CONVERT_TIMEZONE( source_tz, target_tz, source_timestamp_ntz), but again if we are different timezones depending on the server the DEFAULT is executing on I'd think this would fail as well.
https://docs.snowflake.net/manuals/sql-reference/functions/convert_timezone.html

I believe the problem is that the TIMESTAMP data type defaults to TIMESTAMP_NTZ unless you set the Parameter TIMESTAMP_TYPE_MAPPING = TIMESTAMP_LTZ
Since CURRENT_TIMESTAMP() produces a TIMESTAMP_LTZ value, the data types don't match.
This seems to work:
CREATE OR REPLACE TABLE TM (
V NUMBER,
T TIMESTAMP DEFAULT CURRENT_TIMESTAMP::TIMESTAMP
);
INSERT INTO TM(V) VALUES(12345);
SELECT * FROM TM;
V T
12345 2019-11-21 19:03:57.098

THE ANSWER: USE DATA TYPE TIMESTAMP_LTZ(9) INSTEAD OF TIMESTAMP FOR THE DDL FOR THE COLUMN (see below)
In order to have the date/time come back in the format of whatever you have your session in, it has to be stored in the table with a column defined as a Local Time Zone value, then use ALTER SESSION later on to select it. This is how the objects in the Information Schema store Timestamps - with data type TIMESTAMP_LTZ(9).
Here's the final code and results
CREATE OR REPLACE TABLE "EDW_ADMIN"."ETL_SPROC_LOG" (
"ETL_SPROC_LOG_ID" NUMBER IDENTITY NOT NULL,
"OBJECT_NAME" VARCHAR2(250 CHAR) NOT NULL,
"LOG_ENTRY" VARCHAR2(1000 CHAR) NOT NULL,
"DYNAMIC_SQL" VARCHAR2(10000 CHAR) NULL,
"DURATION" NUMBER NULL,
"ROWS_AFFECTED" NUMBER NULL,
"ERROR_CODE" VARCHAR2(200 CHAR) NULL,
"ERROR_DESC" VARCHAR2(4000 CHAR) NULL,
"CREATE_DT" TIMESTAMP_LTZ(9) DEFAULT CURRENT_TIMESTAMP(),
"CREATE_USER" VARCHAR2(50) NOT NULL DEFAULT CURRENT_USER()
);
-- Unit test the new tables identity column and defaults
INSERT INTO edw_admin.ETL_SPROC_LOG (OBJECT_NAME, LOG_ENTRY) VALUES ('OBJ', 'ENTRY1');
ALTER SESSION SET TIMEZONE = 'America/New_York';
select create_dt from etl_sproc_log;
2019-11-21 15:04:50.108 -0500
ALTER SESSION SET TIMEZONE = 'America/Los_Angeles';
select create_dt from etl_sproc_log;
2019-11-21 12:04:50.108 -0800
ALTER SESSION SET TIMEZONE = 'GMT';
select create_dt from etl_sproc_log;
2019-11-21 20:04:50.108 +0000
ALTER SESSION UNSET TIMEZONE;
select create_dt from etl_sproc_log;
2019-11-21 12:04:50.108 -0800
truncate table edw_admin.etl_sproc_log;

Related

Force MySQL to update TIMESTAMP column

I believe I have set my 5.6.17 ver MySQL server to recognize IANA TZ Databases as evidenced by
a system_time_zone variable being set to "Pacific Daylight Time"
a time_zone variable being set to UTC
NOW(), giving me a standard SQL format date time
I thought that that would be sufficient to create an auto updating time stamp field, but, if I create a table via:
CREATE TABLE test (
id SERIAL,
stamp TIMESTAMP,
stuff VARCHAR(255)
);
INSERT INTO test ( stuff ) VALUES ( 'abc' );
SELECT * FROM test;
records seem to be created with NULL in the stamp field:
id stamp stuff
1 NULL abc
I thought that maybe the date gets entered only when doing an update, but when I update:
UPDATE test SET note = 'xyz' WHERE id = 1;
still the stamp is NULL
id stamp stuff
1 NULL xyz
I attempted to change the create as
stamp TIMESTAMP DEFAULT NOW(),
which provides a proper value, but the stamp field remains unchanged when I update (even minutes later).
I also attempted to use
stamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
which, also, gave me an initial value, but never changed when updating.
Also, attempting to append AUTO_INCREMENT didn't seem to work for me. Did I mention that I'm a MySQL newb?
How do I force my TIMESTAMP field to fill at creation and modify when updated?
A field with type TIMESTAMP is also just another field without any special properties like auto initialization or update.
DEFAULT CURRENT_TIMESTAMP only sets the current timestamp when you create the row.
You are looking for the property ON UPDATE CURRENT_TIMESTAMP. This will set the timestamp each time you update the row, given that at least one of the row's values actually changes.
For more infos, have a look at the MySQL docs regarding Automatic Initialization and Update for TIMESTAMP.
Bottom line, create your table like this and stamp will always give you the timestamp of the last change:
CREATE TABLE test (
id SERIAL,
stamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
stuff VARCHAR(255)
);
Sorry can't comment without enough reputation, and I don't know what is IANA TZ Database
But you can try to add On update CURRENT_TIMESTAMP when you create the table:
CREATE TABLE test (
id SERIAL,
stamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,`
stuff VARCHAR(255)
)
it is quite simple
update table set fieldname=now() where fieldname = value;
here we assume that field we try to update is timestamp type field

Create a column 'Date' with default value current datetime MYSQL

Following is my SQL query, it throws an error:-
CREATE TABLE IF NOT EXISTS USER_PROFILE(Id INT PRIMARY KEY AUTO_INCREMENT, date DATETIME NOT NULL DEFAULT NOW) ;
It says Invalid default value for 'date'.
I've tried synonyms for NOW() as well, namely CURRENT_TIMESTAMP, but still the same error.
How can I create a column date with default value current time?
On the documentation page, it says to assign this way
CREATE TABLE t1 (
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
dt DATETIME DEFAULT CURRENT_TIMESTAMP
);
From the document
The DEFAULT value clause in a data type specification indicates a
default value for a column. With one exception, the default value must
be a constant; it cannot be a function or an expression. This means,
for example, that you cannot set the default for a date column to be
the value of a function such as NOW() or CURRENT_DATE. The exception
is that you can specify CURRENT_TIMESTAMP as the default for TIMESTAMP
and DATETIME columns
So no function is allowed in the default value hence the first query is failing.
Again from the document
As of MySQL 5.6.5, TIMESTAMP and DATETIME columns can be automatically
initializated and updated to the current date and time (that is, the
current timestamp). Before 5.6.5, this is true only for TIMESTAMP, and
for at most one TIMESTAMP column per table. The following notes first
describe automatic initialization and updating for MySQL 5.6.5 and up,
then the differences for versions preceding 5.6.5.
Before 5.6.5, this is true only for TIMESTAMP
So your mysql version is less than 5.6.5 hence the 2nd query is failing too.
So you need to create the table as
CREATE TABLE IF NOT EXISTS
USER_PROFILE
(
Id INT PRIMARY KEY AUTO_INCREMENT,
date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ;
It might be that DATE, as a reserved word, is confusing it by the time it gets to the DEFAULT clause. Try a different name and if that works, try quoting "date".

What is automatically populating this column?

I am using MySQL 5.6.1 on a Win 7 64Bit.
I have a standard audit column I add to all my tables called CRT_TS (create timestamp), along with a UPD_TS (update timestamp) column. I had planned on populating these via a before insert trigger and a before update trigger using utc_timestamp().
The UPD_TS column behaves as I expect it to. However, the CRT_TS column seems to be getting automatically populated without my defining a default or trigger for that column.
I was able to reproduce this behavior by running the following script.
create schema `test` default character set utf8 collate utf8_general_ci;
drop table test.TEST_TABLE;
create table test.TEST_TABLE(
TEST_ID int not null auto_increment ,
CRT_TS timestamp not null ,
UPD_TS timestamp not null ,
TEST_ALIAS varchar(64) not null ,
primary key PK_PERM (TEST_ID) ,
unique index UI_PERM_01 (TEST_ALIAS) )
auto_increment = 1001;
insert into test.TEST_TABLE
(TEST_ID
,TEST_ALIAS)
values
(1
,'testing');
select *
from test.TEST_TABLE;
In the above example, the CRT_TS column isn't being supplied a value, and yet it is being populated with the same value what would have been provided by the now() function. The UPD_TS column is populated with all zeros, yet both columns have been defined identically.
My questions is, what is populating the CRT_TS column? I am attempting to set both the UPD_TS and CRT_TS columns to utc_timestamp() value. Even setting the value in a trigger for CRT_TS, the value is overridden.
Thanks for any clarity you can provide.

INSERT current date or time into MySQL

If I create a table with an entity that is suppose to be DATE and when I Insert and leave that column blank shouldn't it display the current date? Same with time?
For example...
CREATE TABLE Register
(
Name CHAR(20) NOT NULL,
Date DATE,
Time TIME
);
Then I Insert:
INSERT INTO Register (Name)
VALUES ('Howard');
I want it to display on the table:
Howard | 5/6/2014 | 8:30 PM
But instead it displays:
Howard | NULL | NULL
Is this incorrect and if so what am I suppose to Insert to allow the current date and time of insert to display?
Firstly, you should have a PRIMARY KEY in your table.
Secondly, you have not set default values for columns Date and Time. Also, you can't set them separately for the DATE and TIME types – you should use TIMESTAMP type and DEFAULT CURRENT_TIMESTAMP like :
CREATE TABLE Register (
Name CHAR(20) PRIMARY KEY NOT NULL,
Date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Thirdly, if you want to use exactly two columns for date storing, you can set a trigger on INSERT event for this table, like it is shown below :
CREATE TRIGGER default_date_time
BEFORE INSERT ON my_table_name
FOR EACH ROW
BEGIN
SET NEW.Date = CURDATE();
SET NEW.Time = CURTIME();
END;
$$
You need to set a default. So you might think you could do this:
CREATE TABLE Register
(
Name CHAR(20) NOT NULL,
Date DATE DEFAULT CURRENT_DATE,
Time TIME DEFAULT CURRENT_TIME
);
But that won’t work. You need to use CURRENT_TIMESTAMP and change your DB structure to use the combined TIMESTAMP format:
CREATE TABLE Register
(
Name CHAR(20) NOT NULL,
Timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
The reason being is there is no MySQL DEFAULT value for DATE or TIME alone. Some clues to that behavior here:
The DEFAULT value clause in a data type specification indicates a
default value for a column. With one exception, the default value must
be a constant; it cannot be a function or an expression. This means,
for example, that you cannot set the default for a date column to be
the value of a function such as NOW() or CURRENT_DATE. The exception
is that you can specify CURRENT_TIMESTAMP as the default for a
TIMESTAMP column. See Section 11.3.5, “Automatic Initialization and
Updating for TIMESTAMP”.
Here are two options:
Get rid of Date and Time columns and add time stamp
INSERT INTO Register (Name,Ctime) VALUES ('Howard',CURRENT_TIMESTAMP);
If you want to continue with your table structure
INSERT INTO Register (Name,Date,Time) VALUES ('Howard',CURDATE(), CURTIME());
Also Note that date and time are reserved words of MySQL and hence should be quoted with backticks to avoid conflicting with reserved words. Or just rename it according to a table name format.

What is the default value for a field if no default value is provided?

I hope this isn't a dumb question. You can set a default value for all variables or a function for when it is inserted. but if the field is not required to insert and you don't allow null values, what is the "blank" value that you see in phpMyAdmin? in a query is it returned as empty string, etc?
just trying to figure it out, I want to query for all records such that the value for a specific column in that record is not "empty" or blank or whatever.
thanks.
Referring to the manual,
For data entry for a NOT NULL column that has no explicit DEFAULT
clause, if an INSERT or REPLACE statement includes no value for the
column, or an UPDATE statement sets the column to NULL, MySQL handles
the column according to the SQL mode in effect at the time:
If strict SQL mode is not enabled, MySQL sets the column to the implicit default value for the column data type.
If strict mode is enabled, an error occurs for transactional tables and the statement is rolled back. For nontransactional tables, an
error occurs, but if this happens for the second or subsequent row of
a multiple-row statement, the preceding rows will have been inserted.
So your question now may be, what are the implicit default values for the various column data types? Here you go:
Implicit defaults are defined as follows:
For numeric types, the default is 0, with the exception that for integer or floating-point types declared with the AUTO_INCREMENT
attribute, the default is the next value in the sequence.
For date and time types other than TIMESTAMP, the default is the appropriate “zero” value for the type. For the first TIMESTAMP column
in a table, the default value is the current date and time. See Section 10.3, “Date and Time Types”.
For string types other than ENUM, the default value is the empty string. For ENUM, the default is the first enumeration value.
There IS no default value unless you specify one (i.e. unless you define a "default constraint" for the column in question).
Here's an example for adding a default on an existing column:
ALTER TABLE dbo.customer ALTER COLUMN contactname SET DEFAULT 'Unknown'
Here's an example creating the table with a default:
CREATE TABLE Books (
ID SMALLINT NOT NULL,
Name VARCHAR(40) NOT NULL,
PubID SMALLINT NOT NULL DEFAULT 0
)
It's good practice to declare ALL columns "not null", and provide default constraints as appropriate.
In the "books" example above, if you "insert" without specifying PubID, the PubID will be zero.
In the same example, if you "insert" without specifying ID or Name ... you'll get an error.
If you want MySQL to auto-assign an ID, use this syntax instead:
CREATE TABLE Books (
ID SMALLINT NOT NULL AUTO_INCREMENT,
Name VARCHAR(40) NOT NULL,
PubID SMALLINT NOT NULL DEFAULT 0
)
If you want to disallow null :-
alter table YOUR_TABLE modify column COLUMN varchar(255) not null default '';
The above query will disallow null and assign an empty string when the value is not supplied.
In phpmysqladmin, blank = empty.
Via PHP mysqli function or mysql function, null value is returned as null still.
Once you have apply the query, you can easily filter that by using
select ... from YOUR_TABLE
where COLUMN != ""; <-- no need to check is null
<-- because the first query already enforce not null
However, is best for you do this before perform the alter :-
update YOUR_TABLE set COLUMN = ""
where COLUMN is null;