How to convert time without time zone to timestamp without time zone? - sql

I need to convert couple of columns in one table in PSQL and I really dont want to drop the table to fix this (thats my last resort). Is there a way to do this, because when I write:
ALTER TABLE table ALTER TABLE column type TIMESTAMP without time zone using column::TIMESTAMP without time zone;
it doesnt work, says:
ERROR:cannot cast type time without time zone to timestamp without time zone.
P.S. If its possible, I would like to avoid dropping columns because I already use indexes of those columns.

If you want the date part to be today:
alter table the_table
alter column the_column type timestamp without time zone
using current_date + the_column

Postgresql will not directly allow to convert time without zone to timestamp without time zone.
You just need to convert first into time without time zone to character varying then change to character varying to timestamp without time zone
You can refer the following query
Changing to character varying:
ALTER TABLE table_name
ALTER COLUMN colum_name TYPE character varying
USING column_name::character varying
Now to change to Timestamp without time zone:
ALTER TABLE table_name
ALTER COLUMN colum_name TYPE Timestamp without time zone
USING column_name::Timestamp without time zone
Now you will be able update successfully.

Related

PostgreSQL: Alter column type without data conversion for compatible types

I have a large table shipments with the column time which has the data type timestamp(0) with time zone, i.e. all microseconds are rounded by PostgreSQL to seconds.
I'd like to convert time's data type to allow microseconds, i.e. timestamp with time zone, but the table is large, so I'd like to alter the type:
ALTER TABLE shipments
ALTER COLUMN time
TYPE timestamptz;
...but do not convert data stored in this column, taking into account timestamp(0) and timestamp are perfectly compatible - because in my case data conversion will take a lot of time. How can I accomplish this?
Thanks in advance!
ALTER TABLE shipments ALTER COLUMN time TYPE timestamptz
won't convert the data which are already stored in your table.
Only the new inserted data and updated data will be stored with the microseconds.
See the demo in dbfiddle.
Widening the value is not a problem. But changing from 'without timezone' to 'with timezone' probably is. It will not rewrite the table if your setting of "timezone" at the time you run the command is 'UTC'.
If the setting is not UTC, then it will need to rewrite the table so it can apply the offset. (I don't know that I agree this is what it should do, I haven't thought it through before. But nonetheless that is what it does do.)

How to convert a timestamp field to int8? Or just drop the column and make a new one?

I have a PostgreSQL table with a column of type timestamp. I had included this column a while ago just in case I wanted to use it for something in the future. I am now looking to convert it into an int8 and use it as an epoch time column. All rows of the table have this column set to null at the moment. When I try to alter the row using:
ALTER TABLE public.new_ambient_data
ALTER COLUMN sensor_date TYPE int8 USING sensor_date::int8;
I get the error:
ERROR: cannot cast type timestamp without time zone to bigint
Is it better to just drop the column and make a new one of the data type that I want, or is here a better SQL script to convert the empty timestamp column to an int8.
Note: The table in question has over a million rows in it.
First of all, the objective is undefined without clearing up what that int8 is going to represent. Seconds since the epoch? Milliseconds? Microseconds? (Won't matter in your particular case with all NULL values, but the next reader might be misguided.)
Next, in Postgres there is no cast defined for timestamp --> bigint (basically for the same reason). You need a valid expression for the USING clause.
Assuming you want microseconds because that's preserving the original microsecond resolution of Postgres timestamps, this will do the job:
ALTER TABLE public.new_ambient_data
ALTER COLUMN sensor_date TYPE int8 USING (extract(epoch FROM sensor_date)*1000000)::int8;
Notably, the Postgres epoch for timestamps starts at 2000-01-01 00:00:00 UTC, unlike the UNIX epoch starting at 1970-01-01 00:00:00 UTC. But extract() returns the UNIX epoch (which can be converted back to timestamptz with to_timestamp()). So just converting the internal value wouldn't do.
For your particular case (all values NULL), it's simpler to use text as stepping stone. Every type can be cast from and to text (as long as the value is compatible).
ALTER TABLE public.new_ambient_data
ALTER COLUMN sensor_date TYPE int8 USING sensor_date::text::int8;
And yes, it's probably cheaper to convert the column in place, than to drop and recreate it. While the column is all NULL, the operation is very cheap either way, as there is no actual tuple data, only a bit in the NULL bitmap. Neither way will trigger a table rewrite.
A newly added column always goes to the end of the columns list, while the converted one stays in place. Depends on what you want.
Finally, don't do it at all. The data type timestamp (or timestamptz) is typically superior to storing temporal information as generic bigint in multiple ways. See details in Laurenz' answer!
See:
Ignoring time zones altogether in Rails and PostgreSQL
How to get the date and time from timestamp in PostgreSQL select query?
How to round off milliseconds value from timestamp(0) in PostgreSQL?
First, I want to dissuade you from doing that. It is much better to use a timestamp column than to use a numeric column:
the values can more easily be understood by a human
you can make use of date arithmetic, so you don't lose anything:
timestamp - timestamp → interval
timestamp + interval → timestamp
interval / double precision → interval
This makes your queries more readable
if you use timestamp with time zone, you can have PostgreSQL handle time zone conversions for you
useful functions like date_part and date_trunc (and date_bin from v14 on!) to truncate the values and extract individual components
Internally, a timestamp is stored as a number anyway, so you don't lose performance.
The actual conversion is given in Erwin's answer, so I won't repeat that here.

Presto: Publish a table with timezone altered to the correct zone

I am trying to change the timezone of a timestamp in presto, however, as I convert the type of column back to timestamp, the timezone correction is reverted. I need to convert it to timestamp/bigint/string to be able to store the data in a schema as the schema does not store the column type timestamp-timezone. I have tried
SELECT FROM_UNIXTIME(CAST(to_unixtime(CAST('2012-10-31 01:00' AS timestamp) AT TIME ZONE 'US/Pacific') * 1000 AS bigint)/1000);
PostgreSQL => ALTER TABLE without timezone -> with timezone, using select for TZ
Alter timezone constraint PostgreSQL
Can you use a column for the timezone parameter of AT TIME ZONE in Presto / Athena?
How do I convert a string which is actually a date with timezone to a timestamp in Presto?
But have not been able to solve the issue. Is there a way I can store the timezone appended date column in the table without it being reverted?
Thank you!
SELECT CAST(SUBSTR(CAST((FROM_UNIXTIME(CAST(1578514469000 AS BIGINT)/1000) AT TIME ZONE 'US/Pacific') AS varchar), 1, 23) AS timestamp)

HSQLDB - ON UPDATE CURRENT_TIMESTAMP with TIMESTAMP column

With this table definition:
CREATE TABLE T1 (C1 TIMESTAMP DEFAULT NOW() ON UPDATE CURRENT_TIMESTAMP NOT
NULL);
when a row is updated C1 is set to the current UTC timestamp.
This is what I want however I was wondering if this is also the intended behavior of HSQLDB since CURRENT_TIMESTAMP returns a value of TIMESTAMP WITH TIME ZONE type.
HSQLDB implements the ISO SQL:2016 Standard. The LOCALTIMESTAMP and CURRENT_TIMESTAMP are Standard functions and return TIMESTAMP values WITHOUT or WITH TIME ZONE respectively. The Standard mandates silent two-way conversion between TIMESTAMP values with or without time zone. Therefore the value returned from CURRENT_TIMEZONE is converted to a value without time zone. This is done by discarding the time zone information.

Change column type from timestamp WITHOUT time zone to timestamp WITH time zone

I found this ALTER COLUMN statement in the PostgreSQL 9.3 ALTER TABLE manual page:
ALTER TABLE audits
ALTER COLUMN created_at SET DATA TYPE timestamp with time zone
USING
timestamp with time zone 'epoch' + created_at * interval '1 second';
I cannot seem to get this to work. I'm getting this error:
ERROR: operator does not exist: timestamp without time zone * interval
SQL state: 42883
Hint: No operator matches the given name and argument type(s).
You might need to add explicit type casts.
The ALTER TABLE statement looks very straight-foward. But I've tried all kinds of casts and converting column-types, but can not get this to work. What am I missing?
The example in the Postgres manual (as well as the working fiddle by #mvp) transform an integer column (representing a UNIX epoch) to timestamptz.
The error message as well as your title clearly indicate you are trying to convert a timestamp to timestamptz. And this just works automatically, without explicit cast.
ALTER TABLE test ALTER created_at TYPE timestamptz;
-> SQLfiddle.
More about timestamp vs. timestamptz:
Ignoring timezones altogether in Rails and PostgreSQL
timestamp values are always interpreted according to the time zone setting of your session. To assume the time zone UTC for the conversion:
BEGIN;
SET LOCAL timezone='UTC';
ALTER TABLE test ALTER created_at TYPE timestamptz;
COMMIT;
Or use the AT TIME ZONE construct:
ALTER TABLE test ALTER created_at TYPE timestamptz
USING created_at AT TIME ZONE 'UTC';
You can assume any time zone this way.
It works fine for me: SQLFiddle.
I think what you have is your SQL client caching data types. I had this issue with mine until I restarted it, and type was indeed changed fine.