Description
There is a complex project details of which are out of scope of this ticket. There is a initial SQL file. There is a migration.
Problem
Migration fails.
The model
CREATE TYPE plugin_status AS ENUM (
'uninstalled',
'installing',
'installed',
'uninstalling',
'error'
);
...
CREATE TABLE test_agent_plugin_status (
id uuid DEFAULT gen_random_uuid () PRIMARY KEY,
status plugin_status DEFAULT 'uninstalled',
);
Migration
Variant 1
-- +migrate Up
BEGIN;
ALTER TABLE test_agent_plugin_status
ALTER status TYPE text;
CREATE TYPE plugin_status_new AS ENUM (
'uninstalled',
'installing',
'installed',
'uninstalling'
);
ALTER TABLE test_agent_plugin_status
ALTER status TYPE plugin_status_new
USING status::plugin_status_new;
DROP TYPE plugin_status;
ALTER TYPE plugin_status_new RENAME TO plugin_status;
COMMIT;
Variant 2
-- +migrate Up
ALTER TABLE test_agent_plugin_status
ALTER status TYPE text;
DROP TYPE plugin_status;
CREATE TYPE plugin_status AS ENUM (
'uninstalled',
'installing',
'installed',
'uninstalling'
);
ALTER TABLE test_agent_plugin_status
ALTER status TYPE plugin_status
USING test_agent_plugin_status::plugin_status;
-- +migrate Down
The error message says.
Banging the head against the wall for couple of hours now. The project is complex. Powered by Kubernetes and Go.
Does the PostgreSQL commands look correct? It seems like whenever the migration is ran it is never executed as a whole.
It seems that the DEFAULT clause of the enum column is the problem
ALTER TABLE test_agent_plugin_status
ALTER status TYPE plugin_status_new
USING status::plugin_status_new;
-- SQL Error [42804]: ERROR: default for column "status" cannot be cast automatically to type plugin_status_new
A possible workaround is to drop the DEFAULT clause and create is again with the new enum type
alter table test_agent_plugin_status
ALTER column status drop default;
ALTER TABLE test_agent_plugin_status
ALTER status TYPE plugin_status_new
USING status::plugin_status_new;
alter table test_agent_plugin_status
ALTER column status set default 'uninstalled'::plugin_status_new;
Related
I have a custom type in Postgres DB called money_with_currency Created as:
CREATE TYPE public.money_with_currency AS (currency_code char(3), amount numeric);
We want to change the type of currency_code from char(3) to varchar.
I thought the code would be something like:
ALTER TYPE public.money_with_currency ALTER ATTRIBUTE currency_code SET DATA TYPE varchar;
But got an error:
ALTER TYPE public.money_with_currency ALTER ATTRIBUTE currency_code SET DATA TYPE varchar;\n"
** (Postgrex.Error) ERROR 0A000 (feature_not_supported) cannot alter type "money_with_currency" because column "prog_fees.amount" uses it
Any thoughts if there is a solution without having to do manual migration to all columns using the type?
First create another custom type and use an alter table query to change the column type of the prog_fees. Then alter the type of public.money_with_currency. Then again execute a alter query to table using public.money_with_currency type. Then it will work
You will need to create a new type with the desired structure. But as there is no direct cast from the old to the new type, you need to use a row constructor when altering the type of the existing column:
CREATE TYPE money_with_currency_new AS (currency_code text, amount numeric);
alter table prog_fees
alter column amount type money_with_currency_new
using ((amount).currency_code, (amount).amount)::money_with_currency_new;
Note the parentheses around the column name when referencing the type's attributes. They are required.
After that you can drop the old type and rename the new type to the old name:
drop type money_with_currency;
alter type money_with_currency_new
rename to money_with_currency;
I have the following query to alter my customer table to add a column for checking if a customer is active or not.
ALTER TABLE COMPANY.CUSTOMER
ADD (isActive VARCHAR2(18 CHAR) DEFAULT 'FALSE' NOT NULL)
CHECK(isActive in ('TRUE','FALSE'));
I get the following error:
RA-01735: invalid ALTER TABLE option
01735. 00000 - "invalid ALTER TABLE option"
I tried to change the order and still did not work. can you help me with why it is failing to alter the table?
Also how to ensure if TRUE or FALSE is always uppercase when inserting?
You can split up the CHECK constraint from the ADD COLUMN for one route...
/* drop table customer_so purge; */
create table customer_so (id integer, name varchar2(50));
ALTER TABLE CUSTOMER_SO
ADD (ISACTIVE VARCHAR2(20) DEFAULT 'FALSE' );
ALTER TABLE CUSTOMER_SO
ADD CONSTRAINT CUSTOMER_SO_CHK1 CHECK
(ISACTIVE IN ('TRUE', 'FALSE'))
ENABLE;
Or, like you had, all in one go -
/* drop table customer_so purge; */
create table customer_so (id integer, name varchar2(50));
ALTER TABLE CUSTOMER_SO
ADD (ISACTIVE VARCHAR2(20) DEFAULT 'FALSE' constraint CUSTOMER_SO_CHK1 CHECK
(ISACTIVE IN ('TRUE', 'FALSE')));
So basically end of the day, you're missing the 'CONSTRAINT' keyword.
Since you tagged oracle-sqldeveloper, you should know the EDIT TABLE ddialog lets you click through these changes, and will generate the DDL for you -
Finally, by default, strings in Oracle are case-sensitive, so your check constraint will work as desired.
I have a primary key column in my SQL table in PostgreSQL named "id". It is a "bigseries" column. I want to convert the column to a "UUID" column. It entered the below command in the terminal:
alter table people alter column id uuid;
and
alter table people alter column id uuid using (uuid_generate_v4());
but neither of them worked.
In both tries I got the error message
ERROR: syntax error at or near "uuid"
LINE 1: alter table people alter column id uuid using (uuid_generate...
What is the correct syntax?
First of all uuid_generate_v4() is a function which is provided by an extension called uuid-ossp. You should have install that extension by using;
CREATE EXTENSION uuid-ossp;
Postgresql 13 introduced a new function which does basically the same without installing extension. The function is called gen_random_uuid()
Suppose that we have a table like the one below;
CREATE TABLE people (
id bigserial primary key,
data text
);
The bigserial is not a real type. It's a macro which basically creates bigint column with default value and a sequence. The default value is next value of that sequence.
For your use case, to change data type, you first should drop the old default value. Then, alter the type and finally add new default value expression. Here is the sample:
ALTER TABLE people
ALTER id DROP DEFAULT,
ALTER id TYPE uuid using (gen_random_uuid() /* or uuid_generate_v4() */ ),
ALTER id SET DEFAULT gen_random_uuid() /* or uuid_generate_v4() */ ;
CREATE TABLE IF NOT EXISTS people (
id uuid NOT NULL CONSTRAINT people_pkey PRIMARY KEY,
address varchar,
city varchar(255),
country varchar(255),
email varchar(255),
phone varchar(255)
);
This is the correct syntax to create table in postgres SQL, it's better to do these constraints at beginning to avoid any error.
For using alter command you would do the following:
ALTER TABLE customer ADD COLUMN cid uuid PRIMARY KEY;
Most of errors that you could find while writing command either lower case or undefined correct the table name or column.
I am trying to change the column size from 100 to 150 varchar data type using following query:
alter table data_warehouse.tbl_abc
alter column first_nm varchar(150) null;
Getting the following error:
SQL Error [42601]: ERROR: syntax error at or near "varchar"
Position: 77
The syntax is a bit different, so try this:
ALTER TABLE data_warehouse.tbl_abc
ALTER COLUMN first_nm type varchar(120);
The error in your syntax is that you missed a TYPE keyword:
ALTER TABLE data_warehouse.tbl_abc
ALTER COLUMN first_nm TYPE varchar(150);
and if you have a NOT NULL constraint you want to remove, add a new ALTER COLUMN inside the same ALTER TABLE statement:
ALTER TABLE data_warehouse.tbl_abc
ALTER COLUMN first_nm TYPE varchar(150),
ALTER COLUMN first_nm DROP NOT NULL;
for reference look here: https://www.postgresql.org/docs/current/sql-altertable.html
Edit: as in the comment, if you have a view which involves the same column, drop it and re-create it under transaction:
BEGIN TRANSACTION;
DROP VIEW [...];
ALTER TABLE [...];
CREATE VIEW [...];
COMMIT;
Be aware that to alter a table, you must acquire an exclusive lock on it, so during the whole process, all the queries over the same table and on the views of the table are locked, also if they don't read from the altered column (because the whole table is locked) - use with caution in production environment
ALTER TABLE products ALTER COLUMN power_price DROP DEFAULT;
ALTER TABLE products ALTER COLUMN power_price TYPE bool USING (power_price::boolean);
ALTER TABLE products ALTER COLUMN power_price SET NOT NULL;
ALTER TABLE products ALTER COLUMN power_price SET DEFAULT false;
Postgres gives me this error:
Query failed: ERROR: cannot cast type numeric to boolean
Use:
ALTER TABLE products ALTER power_price TYPE bool USING (power_price::int::bool);
There is no direct cast defined between numeric and boolean. You can use integer as middle-ground. text would be another candidate for middle ground, since every type can be cast from / to text. Values have to be 1 / 0 for the text route, of course.
Better yet, do it all in a single command for better performance and shorter lock time:
ALTER TABLE products
ALTER power_price DROP DEFAULT
, ALTER power_price TYPE bool USING (power_price::int::bool)
, ALTER power_price SET NOT NULL
, ALTER power_price SET DEFAULT false;
Details in the manual about ALTER TABLE.