Can't alter column type to a shorter VARCHAR in Redshift. Getting "target column size should be greater or equal to current maximum column size" - sql

I'm trying to run
alter table schema_name.table_name
ALTER COLUMN column_name TYPE varchar(256)
in Amazon Redshift, but I'm getting this error:
SQL Error [500310] [0A000]: Amazon Invalid operation: cannot alter column "column_name" of relation "table_name", target column size 256 should be greater or equal to current maximum column size 879;
I've already tried
update schema_name.table_name
set column_name = CAST(column_name AS VARCHAR(256))
and
update schema_name.table_name
set column_name = SUBSTRING(column_name, 1, 256)
in order to reduce this maximum column size of 879, but I still get the same error. I know I can work around it by creating a new VARCHAR(256) column with the same data, but is there another way?

I believe the answer is 'No, you cannot reduce a varchar column length'. You need to copy the data somewhere else (new table, new column) to reduce the size. Redshift doesn't know if the old data can fit in the new size w/o trying to perform such a copy itself.
You can create a new column of the size you want, update the table to put the data from the old column into this new column (reducing string size if necessary), rename the old column to something unique, rename the new column the same as the old column name, and then drop the unique named column. You will have the same column names as before but the max length of the column in question will be reduced. However the default column order will be different.

CASCADE worked in my case.
drop table dbname.tablename CASCADE;

Related

Oracle will corrupt other column's data after DROP COLUMN [duplicate]

This question already has answers here:
Why does this Oracle DROP COLUMN alter the default value of another column?
(1 answer)
Oracle bug when adding not nullable columns with default
(2 answers)
Closed 1 year ago.
I have a table with some other columns and preexisting data in my development database. I need to add four more columns to store data for a new feature.
I've added four new columns to this table with the following commands:
alter table my_table add (pin_validacao_cadastro varchar2(6 char) default '000000' not null);
alter table my_table add (tentativas_validacao_pin number default 0 not null);
alter table my_table add (codigo_bloqueio number default 1 not null check (codigo_bloqueio in (0, 1, 2)));
alter table my_table add data_validacao_cadastro date;
Then, I've discovered that the first definition needed to change because the default value should be another value. Then, I've dropped the first column (pin_validacao_cadastro).
alter table my_table drop column pin_validacao_cadastro;
Suprisingly enough, before I try to recreate the first column with the correct default value, I've noticed the second column (tentativas_validacao_pin) now is altered and all the values are NULL, when it should to be 0.
Then, I've dropped the second column (tentativas_validacao_pin) to recreate it and fix the corruption.
alter table my_table drop column tentativas_validacao_pin;
But wait! Before I've had the chance to recreate it, I've noticed that all values of the third column (codigo_bloqueio) are equal to 0. Before the DROP command, all values of this column were equal to 1 (the default value for this column).
What am I missing here? Is this supposed to happen? It seems that the default value of the dropped column is being applyed to the next existing column.
Since the problem ocurrs using diferent database tools (sqldeveloper, sqlplus, PlSqldeveloper) I think that it is something related to oracle database.
Can anyone explain what is happening?
I'm using Oracle 11G.

How To Alter Date column to Varchar2(20)? [duplicate]

How can I change DATA TYPE of a column from number to varchar2 without deleting the table data?
You can't.
You can, however, create a new column with the new data type, migrate the data, drop the old column, and rename the new column. Something like
ALTER TABLE table_name
ADD( new_column_name varchar2(10) );
UPDATE table_name
SET new_column_name = to_char(old_column_name, <<some format>>);
ALTER TABLE table_name
DROP COLUMN old_column_name;
ALTER TABLE table_name
RENAME COLUMN new_column_name TO old_coulumn_name;
If you have code that depends on the position of the column in the table (which you really shouldn't have), you could rename the table and create a view on the table with the original name of the table that exposes the columns in the order your code expects until you can fix that buggy code.
You have to first deal with the existing rows before you modify the column DATA TYPE.
You could do the following steps:
Add the new column with a new name.
Update the new column from old column.
Drop the old column.
Rename the new column with the old column name.
For example,
alter table t add (col_new varchar2(50));
update t set col_new = to_char(col_old);
alter table t drop column col_old cascade constraints;
alter table t rename column col_new to col_old;
Make sure you re-create any required indexes which you had.
You could also try the CTAS approach, i.e. create table as select. But, the above is safe and preferrable.
The most efficient way is probably to do a CREATE TABLE ... AS SELECT
(CTAS)
alter table table_name modify (column_name VARCHAR2(255));
Since we can't change data type of a column with values, the approach that I was followed as below,
Say the column name you want to change type is 'A' and this can be achieved with SQL developer.
First sort table data by other column (ex: datetime).
Next copy the values of column 'A' and paste to excel file.
Delete values of the column 'A' an commit.
Change the data type and commit.
Again sort table data by previously used column (ex: datetime).
Then paste copied data from excel and commit.

Alter column of type timestamp

I want to update an empty table , which has a column of type timestamp to varbinary(8)
I used the following command
ALTER TABLE Notification ALTER COLUMN RowRevisionID varbinary(8)
and I get and an error
Cannot alter column 'RowRevisionID' because it is 'timestamp'.
How can I change a timestamp column type?
I do not wish to drop the column an add a new one , because that will create a column at the end , and I wish to preserve column order to use this table in an INSERT INTO
You unfortunately cannot make a change to a timestamp column, as the error implies; you are stuck with what you have. Also, each table can only have one timestamp column, so you cannot duplicate the column in any solution.
Your best bet (depending on the size of the table) might be to copy the data into a staging table (using SELECT * INTO MyTempTable FROM OriginalTable syntax to preserve the timestamp values), then drop and recreate the original table with the desired columns in the desired order and reinsert the data, or you could add a new VARBINARY(8) column to the existing table and drop the timestamp column, preserving the original table. There are probably other solutions along the same lines as these, but all will require a new column, rather than an ALTER COLUMN script.
You are looking for:
ALTER TABLE Notification DROP RowRevisionID;
and
ALTER TABLE Notification ADD RowRevisionID varbinary(8) AFTER myOtherColumn;

Alter the data type of a column in MonetDB

How can I alter the type of a column in an existing table in MonetDB? According to the documentation the code should be something like
ALTER TABLE <tablename> ALTER COLUMN <columnname> SET ...
but then I am basically lost because I do not know which standard the SQL used by MonetDB follows here and I get a syntax error. If this statement is not possible I would be grateful for a workaround that is not too slow for large (order of 10^9 records) tables.
Note: I ran into this problem while doing some bulk data imports from csv files into a table in my database. One of the columns is of type INT but the values in the file at some point exceed the INT limit of 2^31-1 (yes, the table is big) and so the transaction aborts. After I found out the reason for this failure, I wanted to change it to BIGINT but all versions of SQL code I tried failed.
This is currently not supported. However, there is a workaround:
Example table for this example, say we want to change the type of column b from integer to double.
create table a(b integer);
insert into a values(42);
Create a temporary column alter table a add column b2 double;
Set data in temporary column to original data update a set b2=b;
Remove the original column alter table a drop column b;
Re-create the original column with the new type alter table a add column b double;
Move data from temporary column to new column update a set b=b2;
Drop the temporary column alter table a drop column b2;
Profit
Note that this will change the ordering of columns if there are more than one. However, this is only a cosmetic issue.

Postgresql - change the size of a varchar column to lower length

I have a question about the ALTER TABLE command on a really large table (almost 30 millions rows).
One of its columns is a varchar(255) and I would like to resize it to a varchar(40).
Basically, I would like to change my column by running the following command:
ALTER TABLE mytable ALTER COLUMN mycolumn TYPE varchar(40);
I have no problem if the process is very long but it seems my table is no more readable during the ALTER TABLE command.
Is there a smarter way? Maybe add a new column, copy values from the old column, drop the old column and finally rename the new one?
Note: I use PostgreSQL 9.0.
In PostgreSQL 9.1 there is an easier way
http://www.postgresql.org/message-id/162867790801110710g3c686010qcdd852e721e7a559#mail.gmail.com
CREATE TABLE foog(a varchar(10));
ALTER TABLE foog ALTER COLUMN a TYPE varchar(30);
postgres=# \d foog
Table "public.foog"
Column | Type | Modifiers
--------+-----------------------+-----------
a | character varying(30) |
There's a description of how to do this at Resize a column in a PostgreSQL table without changing data. You have to hack the database catalog data. The only way to do this officially is with ALTER TABLE, and as you've noted that change will lock and rewrite the entire table while it's running.
Make sure you read the Character Types section of the docs before changing this. All sorts of weird cases to be aware of here. The length check is done when values are stored into the rows. If you hack a lower limit in there, that will not reduce the size of existing values at all. You would be wise to do a scan over the whole table looking for rows where the length of the field is >40 characters after making the change. You'll need to figure out how to truncate those manually--so you're back some locks just on oversize ones--because if someone tries to update anything on that row it's going to reject it as too big now, at the point it goes to store the new version of the row. Hilarity ensues for the user.
VARCHAR is a terrible type that exists in PostgreSQL only to comply with its associated terrible part of the SQL standard. If you don't care about multi-database compatibility, consider storing your data as TEXT and add a constraint to limits its length. Constraints you can change around without this table lock/rewrite problem, and they can do more integrity checking than just the weak length check.
Ok, I'm probably late to the party, BUT...
THERE'S NO NEED TO RESIZE THE COLUMN IN YOUR CASE!
Postgres, unlike some other databases, is smart enough to only use just enough space to fit the string (even using compression for longer strings), so even if your column is declared as VARCHAR(255) - if you store 40-character strings in the column, the space usage will be 40 bytes + 1 byte of overhead.
The storage requirement for a short string (up to 126 bytes) is 1 byte
plus the actual string, which includes the space padding in the case
of character. Longer strings have 4 bytes of overhead instead of 1.
Long strings are compressed by the system automatically, so the
physical requirement on disk might be less. Very long values are also
stored in background tables so that they do not interfere with rapid
access to shorter column values.
(http://www.postgresql.org/docs/9.0/interactive/datatype-character.html)
The size specification in VARCHAR is only used to check the size of the values which are inserted, it does not affect the disk layout. In fact, VARCHAR and TEXT fields are stored in the same way in Postgres.
I was facing the same problem trying to truncate a VARCHAR from 32 to 8 and getting the ERROR: value too long for type character varying(8). I want to stay as close to SQL as possible because I'm using a self-made JPA-like structure that we might have to switch to different DBMS according to customer's choices (PostgreSQL being the default one). Hence, I don't want to use the trick of altering System tables.
I ended using the USING statement in the ALTER TABLE:
ALTER TABLE "MY_TABLE" ALTER COLUMN "MyColumn" TYPE varchar(8)
USING substr("MyColumn", 1, 8)
As #raylu noted, ALTER acquires an exclusive lock on the table so all other operations will be delayed until it completes.
if you put the alter into a transaction the table should not be locked:
BEGIN;
ALTER TABLE "public"."mytable" ALTER COLUMN "mycolumn" TYPE varchar(40);
COMMIT;
this worked for me blazing fast, few seconds on a table with more than 400k rows.
Adding new column and replacing new one with old worked for me, on redshift postgresql, refer this link for more details https://gist.github.com/mmasashi/7107430
BEGIN;
LOCK users;
ALTER TABLE users ADD COLUMN name_new varchar(512) DEFAULT NULL;
UPDATE users SET name_new = name;
ALTER TABLE users DROP name;
ALTER TABLE users RENAME name_new TO name;
END;
Here's the cache of the page described by Greg Smith. In case that dies as well, the alter statement looks like this:
UPDATE pg_attribute SET atttypmod = 35+4
WHERE attrelid = 'TABLE1'::regclass
AND attname = 'COL1';
Where your table is TABLE1, the column is COL1 and you want to set it to 35 characters (the +4 is needed for legacy purposes according to the link, possibly the overhead referred to by A.H. in the comments).
Try run following alter table:
ALTER TABLE public.users
ALTER COLUMN "password" TYPE varchar(300)
USING "password"::varchar;
I have found a very easy way to change the size i.e. the annotation #Size(min = 1, max = 50) which is part of "import javax.validation.constraints" i.e.
"import javax.validation.constraints.Size;"
#Size(min = 1, max = 50)
private String country;
when executing this is hibernate you get in pgAdmin III
CREATE TABLE address
(
.....
country character varying(50),
.....
)