PostgreSQL => ALTER TABLE without timezone -> with timezone, using select for TZ - postgresql

I'm trying to convert the column, and preserve the data in the specified timezone. I have a script, but it errors out on the SELECT at the end.
ALTER TABLE schema.table
ALTER COLUMN column_date TYPE TIMESTAMP WITH TIME ZONE
USING column_date AT TIME ZONE (SELECT value FROM schema.table WHERE id = 'timezone');
ERROR: cannot use subquery in transform expression
I have time zones stored, but trying to pull that back to apply to the script is posing a challenge. I know I can simply hardcode the timezone as 'EST|CST|PST', etc. but I have multiple databases this needs to be applied to (with multiple alters per DB), hence the required SELECT at the end. Is there a way to accomplish this?
I've poured over a few questions on this subject; while some came close, they don't quite meet the needs (My apologies if this is a duplicate, I've spent a while searching for an answer).
[RESOLVED]: Using 2 separate queries
ALTER TABLE schema.table
ALTER COLUMN column_date TYPE TIMESTAMP WITH TIME ZONE;
UPDATE schema.table
SET column_date = column_date AT TIME ZONE
(SELECT value FROM schema.table WHERE id = 'timezone');

You can use dynamic SQL:
DO
$$BEGIN
EXECUTE format('ALTER TABLE ... AT TIME ZONE %L',
(SELECT value FROM atable ...));
END;$$;

Related

How to convert varchar to timestamp in postgreSQL?

I have data as following, But the column type is Varchar:
2019-09-28T23:59:59.52Z
I assume 52 here is milli seconds, If so..
I would like to convert it as following and change the column type to timestamp:
2019-09-28 23:59:59.52
Can someone let me know how I can convert in postgreSQL?
EDIT:
I can see data in table as (since the column type is varchar):
2019-09-28T23:59:59.52Z
Instead, I want data in the table to be shown as:
2019-09-28 23:59:59 ( and may be .52, if possible)
I need to change the column type to timestamp as well, I guess, Please help with that too.
Answer:
Tim has provided a solution, You can follow that.
But, In my case, It is prod env, So, I have just changed the type using:
ALTER TABLE my_table ALTER COLUMN my_column TYPE TIMESTAMP USING my_column::timestamp without time zone;
Thanks
Your timestamp string literal is already in a format which can be directly cast in Postgres:
SELECT '2019-09-28T23:59:59.52Z'::timestamp; -- 2019-09-28 23:59:59.52
As a test, let's add one day to make sure it's working:
SELECT '2019-09-28T23:59:59.52Z'::timestamp + interval '1 day';
-- 2019-09-29 23:59:59.52
If you want to actually add a new timestamp column using string data from another column, then try:
ALTER TABLE yourTable ADD COLUMN new_ts TIMESTAMP;
UPDATE yourTable SET new_ts = old_ts::timestamp;
ALTER TABLE yourTable DROP COLUMN old_ts;
ALTER TABLE yourTable RENAME COLUMN new_ts TO old_ts; -- optional
The last ALTER statement is optional if you want the new bona fide timestamp column to bear the same name as the old text timestamp column.

Huge PostgreSQL table - Select, update very slow

I am using PostgreSQL 9.5. I have a table which is almost 20GB's. It has a primary key on the ID column which is an auto-increment column, however I am running my queries on another column which is a timestamp... I am trying to select/update/delete on the basis of a timestamp column but the queries are very slow. For example: A select on this table `where timestamp_column::date (current_date - INTERVAL '10 DAY')::date) is taking more than 15 mins or so..
Can you please help on what kind of Index should I add to this table (if needed) to make it perform faster?
Thanks
You can create an index with your clause expression:
CREATE INDEX ns_event_last_updated_idx ON ns_event (CAST(last_updated AT TIME ZONE 'UTC' AS DATE));
But, keep in mind that you're using timestamp with timezone, cast this type to date can let you get undesirable side effects.
Also, remove all casting in your sql:
select * from ns_event where Last_Updated < (current_date - INTERVAL '25 DAY');

How do I convert timestamp and offset columns to a single timestamptz column?

Image I have a table containing the following two columns:
timestampwithouttimezone (of type TIMESTAMP WITHOUT TIME ZONE)
utcoffset (of type INTEGER)
I want to convert those two column to a single one of type TIMESTAMP WITH TIME ZONE. Can this be achieved using a ALTER TABLE ALTER COLUMN [column] SET DATE TYPE TIMESTAMP WITH TIME ZONE query and the additional USING clause?
Or do I need a separate UPDATE query that takes the offset and sets the timezone of the timestamps? If that's the case, what would that query be? I can't find any examples that show how to update the timezone using an integer.
You could do that like this, assuming the offset is in hours:
ALTER TABLE mytab
ALTER timestampwithouttimezone
TYPE timestamp with time zone
USING CAST (timestampwithouttimezone::text || ' '
|| to_char(utcoffset, 'S00FM')
AS timestamp with time zone),
DROP utcoffset;

date_trunc on timestamp column returns nothing

I have a strange problem when retrieving records from db after comparing a truncated field with date_trunc().
This query doesn't return any data:
select id from my_db_log
where date_trunc('day',creation_date) >= to_date('2014-03-05'::text,'yyyy-mm-dd');
But if I add the column creation_date with id then it returns data(i.e. select id, creation_date...).
I have another column last_update_date having same type and when I use that one, still does the same behavior.
select id from my_db_log
where date_trunc('day',last_update_date) >= to_date('2014-03-05'::text,'yyyy-mm-dd');
Similar to previous one. it also returns record if I do id, last_update_date in my select.
Now to dig further, I have added both creation_date and last_updated_date in my where clause and this time it demands to have both of them in my select clause to have records(i.e. select id, creation_date, last_update_date).
Does anyone encountered the same problem ever? This similar thing works with my other tables which are having this type of columns!
If it helps, here is my table schema:
id serial NOT NULL,
creation_date timestamp without time zone NOT NULL DEFAULT now(),
last_update_date timestamp without time zone NOT NULL DEFAULT now(),
CONSTRAINT db_log_pkey PRIMARY KEY (id),
I have asked a different question earlier that didn't get any answer. This problem may be related to that one. If you are interested on that one, here is the link.
EDITS:: EXPLAIN (FORMAT XML) with select * returns:
<explain xmlns="http://www.postgresql.org/2009/explain">
<Query>
<Plan>
<Node-Type>Result</Node-Type>
<Startup-Cost>0.00</Startup-Cost>
<Total-Cost>0.00</Total-Cost>
<Plan-Rows>1000</Plan-Rows>
<Plan-Width>658</Plan-Width>
<Plans>
<Plan>
<Node-Type>Result</Node-Type>
<Parent-Relationship>Outer</Parent-Relationship>
<Alias>my_db_log</Alias>
<Startup-Cost>0.00</Startup-Cost>
<Total-Cost>0.00</Total-Cost>
<Plan-Rows>1000</Plan-Rows>
<Plan-Width>658</Plan-Width>
<Node/s>datanode1</Node/s>
<Coordinator-quals>(date_trunc('day'::text, creation_date) >= to_date('2014-03-05'::text, 'yyyy-mm-dd'::text))</Coordinator-quals>
</Plan>
</Plans>
</Plan>
</Query>
</explain>
"Impossible" phenomenon
The number of rows returned is completely independent of items in the SELECT clause. (But see #Craig's comment about SRFs.) Something must be broken in your db.
Maybe a broken covering index? When you throw in the additional column, you force Postgres to visit the table itself. Try to re-index:
REINDEX TABLE my_db_log;
The manual on REINDEX. Or:
VACUUM FULL ANALYZE my_db_log;
Better query
Either way, use instead:
select id from my_db_log
where creation_date >= '2014-03-05'::date
Or:
select id from my_db_log
where creation_date >= '2014-03-05 00:00'::timestamp
'2014-03-05' is in ISO 8601 format. You can just cast this string literal to date. No need for to_date(), works with any locale. The date is coerced to timestamp [without time zone] automatically when compared to creation_date (being timestamp [without time zone]). More details about timestamps in Postgres here:
Ignoring timezones altogether in Rails and PostgreSQL
Also, you gain nothing by throwing in date_trunc() here. On the contrary, your query will be slower and any plain index on the column cannot be used (potentially making this much slower)

how to insert a time in oracle 10g database

I want to insert date and time in oracle database, I have created the table with columns
create table myadmin
( employe_id number(5),
supervisor Varchar2(20),
department Varchar2(20),
action Varchar2(20),
sdate date,
stime date)
While inserting the values below it gives an error. Please tell me how to insert the time ?
insert into myadmin
( employe_id,supervisor,department,action,sdate,stime) values
(83,'gaurav','helpdesk','pick','23-jan-2013','09:43:00');
You have to use keyword to_date for date insert in oracle like this.
to_date('23-01-2013','dd-mm-yyyy')
Basically you have to use keyword to_date('your date','your date format').
You can also add date and time together if you want and it would be something like this
to_date('23-01-2013 09:43:00','dd-mm-yyyy hh24:mi:ss')
A date in Oracle always has a date part and a time part. Having date and time in two separate columns only makes sense, if it can occur that date is null and time is not. (And still, you could set date to an improbable value like 1.1.0001 then.)
However, if you want to stick to those two separate fields, then make your string a datetime with the to_date function specifying the format used:
insert into myadmin
( employe_id,supervisor,department,action,sdate,stime) values
(83,'gaurav','helpdesk','pick',to_date('23-01-2013','dd-mm-yyyy'), to_date('09:43:00', 'hh24:mi:ss'));