Recreate table from a select and add an extra datetime default column (Snowflake) - sql

I'm having problems creating a table that should be pretty straightforward. The SQL code (Snowflake) is:
create or replace table bank_raw as
select
*,
created_at datetime default current_timestamp()
from bank_raw;
My error is: Syntax error: unexpected 'DEFAULT'. (line 12).
I don't know how I can recreate this table and add this default timestamp column. By the way, I have already created multiple tables from scratch with created_at DateTime default current_timestamp().
Any ideas?

It is possible to define column list definition when using CTAS:
Sample data:
CREATE TABLE bank_raw(id INT, col TEXT);
INSERT INTO bank_raw(id, col) VALUES (1, 'a'), (2,'b');
Query:
CREATE OR REPLACE TABLE bank_raw(id INT,
col TEXT,
created_at datetime default current_timestamp())
AS
SELECT
id, col, CURRENT_TIMESTAMP()
FROM bank_raw;
Output:
SELECT * FROM bank_raw;
DESCRIBE TABLE bank_raw;

Since this is a DML operation not a DDL operation, the default keyword does not apply. You can simply remove it and instead project the column and name it:
create or replace table bank_raw as
select
*,
current_timestamp() as created_at
from bank_raw;
Edit: To enforce a default, you cannot alter a table to add a column with a default value except for sequences. So you'd need to do something like this:
select get_ddl('table','BLANK_RAW');
-- Copy and paste the DDL. Rename the new table,
-- and add the default timestamp:
create or replace table A
(
-- Existing columns here then:
created_at timestamp default current_timestamp
);
You can then do an insert from a select on the table BLANK_RAW. You'll need to specify a column list and omit the CREATED_AT column.

Related

Data move from table to table , column type error

I'm using Postgresql with timescaledb extension, pg13 - tsdb 2.2.1
table 1
create table user
(
...
join_dt timestamptz NULL,
...
);
Table 2
create table a_user
(
...
join_dt timestamptz NULL,
...
);
I used SQL insert to a_user table so there's data inside the table, and want to move the data to user table by querying this :
insert into user
select * from a_user;
I get this error:
[42804] ERROR: column "join_dt" is of type timestamp with time zone but expression is of type character varying
The original data comes from a table which is like this
create table ori_user
(
...
join_dt timestamp(6) with time zone,
...
);
I export data as SQL insert form from ori_user, and then inserted into a_user, and now I want to move from a_user to user.
This is what I have tried:
insert into user select
...
join_dt::timestamptz,
...
from a_user;
does not work.
with aa as (select pg_typeof(join_dt)::varchar as type,* from a_user)
select * from aa where aa.type not like 'timestamp with time zone';
shows no row.
any other solutions? please help.
Thanks in advance.
I thought table columns are in same order, but it wasn't.
fix the order, problem solved.

Partition key failing error for postgres table

ERROR: no partition of relation "test_table" found for row DETAIL:
Partition key of the failing row contains (start_time) = (2021-04-25
00:00:00). SQL state: 23514
I am inserting a data where i have a column start time (2021-04-25 00:00:00)
This is my Schema
CREATE TABLE test_table (
start_time timestamp NULL,
)
PARTITION BY RANGE (start_time);
This sounds as if you have no partition-tables defined for this table.
You might need something like this:
CREATE TABLE test_table_2021 PARTITION OF test_table
FOR VALUES FROM ('2021-01-01') TO ('2022-01-01');
After you defined this partition for your partitioned table, you should be able to insert the data (as long as start_time is anywhen in 2021).
See the docs: https://www.postgresql.org/docs/current/ddl-partitioning.html

How to add comparing to ON CONFLICT () DO UPDATE

I need to check, if in table there are any operations with current user for today.
Usually I compare time in this way: timestamp > CURRENT_TIMESTAMP::date
Could you please help, how to do it in INSERT in ON CONFLICT () DO UDPATE?
INSERT INTO table (login, smth, timestamp)
VALUES ('username', 'smth', CURRENT_TIMESTAMP)
ON CONFLICT (login, timestamp) DO UPDATE
SET smth = 'smth'
timestamp = CURRENT_TIMESTAMP
Here will be exactly comparing of timestamp, but I need to check, if it's for today, like above: timestamp > CURRENT_TIMESTAMP::date
Thanks!
If you want to store the timestamp but have a unique constraint on the date, then you can do that easily in the most recent versions of Postgres using a computed column. This requires adding a new column which is the date into the table:
create table t (
login text,
smth text,
ts timestamp,
ts_date date generated always as (ts::date) stored
);
And then creating a unique constraint:
create unique index unq_t_login_timestamp on t(login, ts_date);
Now you can use on conflict:
INSERT INTO t (login, smth, ts)
VALUES ('username', 'smth', CURRENT_TIMESTAMP)
ON CONFLICT (login, ts_date) DO UPDATE
SET smth = 'smth',
ts = CURRENT_TIMESTAMP;
Here is the code in a db<>fiddle.
EDIT:
It is better to eschew the computed column and just use:
create unique index unq_t_login_timestamp on t(login, (timestamp::date));
If you can use CTE, see here.
In case of your question, the query is like below:
(However, I'm not clear what "timestamp > CURRENT_TIMESTAMP::date" means.)
with
"data"("w_login","w_smth","w_timestamp") as (
select 'username2'::text, 'smth'::text, CURRENT_TIMESTAMP
),
"update" as (
update "table" set ("smth","timestamp")=("w_smth","w_timestamp") from "data"
where "login"="w_login" and "w_timestamp">CURRENT_TIMESTAMP::date
returning *
)
insert into "table"
select * from "data"
where not exists (select * from "update");
DB Fiddle

How to add column to database with default

I have a database that I'm trying to add a column to. This column should hold information of the type timestamp, and I want every row to have the same timestamp (the current time) when I'm done.
I currently have tried:
cursor.execute('''ALTER TABLE my_table ADD COLUMN time timestamp DEFAULT ?''', (datetime.datetime.utcnow(),))
Which results in sqlite3.OperationalError: near "?": syntax error.
So then I tried:
cursor.execute(f'''ALTER TABLE my_table ADD COLUMN time timestamp DEFAULT {datetime.datetime.utcnow()}''')
Which results in sqlite3.OperationalError: near "-": syntax error.
Also, doing
cursor.execute(f'''ALTER TABLE my_table ADD COLUMN time timestamp DEFAULT CURRENT_TIMESTAMP''')
results in sqlite3.OperationalError: Cannot add a column with non-constant default.
How can I add the new column and set the values in that column? (Either through DEFAULT, or some other mechanism.)
SQLite does not allow adding a new column with a non-constant value. So this:
alter table my_table add column my_time timestamp default current_timestamp;
... generates error:
Cannot add a column with non-constant default
A simple option would be to recreate the table. Assuming that you have single column called id, that would look like:
create table my_table_new(
id int primary key,
my_time timestamp default current_timestamp
);
insert into my_table_new(id) select id from my_table;
drop table my_table; -- back it up first !
alter table my_table_new rename to my_table;
You can first add the new column and then update every existing row in the table to the desired value:
ALTER TABLE my_table ADD COLUMN time;
UPDATE my_table SET time = CURRENT_TIMESTAMP;

Add a column with the current timestamp to a table in Hive

I'm trying to add a column called tstamp to a table that I've created. The column is to have the current timestamp in the format 'yyyy-MM-dd' populating each row.
I initially created the table from another table (table1) using the statement:
create location2.table2
as (select *
from location1.table1
);
I then used the alter table statement to add a field called tstamp to table2 using the code:
alter table location2.table2
add columns (tstamp date)
and I can see that this has successfully added a column to table2 named tstamp and populated each row of this table as null. I am now trying to insert the current date into every row in the field tstamp but am struggling to do so. I've tried using the insert into statement as:
insert into location2.table2 (tstamp)
values (to_date(current_timestamp()))
but get the error "Expression of type TOK_FUNCTION not supported in insert/values". I then also tried to add just a string and replaced the function with '2019-07-25'. Doing this added a new row to my table with null values in every column except tstamp which had a value '2019-07-25'. I'm now confused as it appears my approach was not the right one for the problem and am unsure where to go from here. Any help would be greatly appreciated.
create location2.table2 as (select current_date as tstamp,* from location1.table1 );