Postgresql query not able to add column where the column name is similar to an SQL keyword? - sql

I have an list of internal names for different columns I need to add, and one is named end which causes an issue since this is an sql keyword.
DO
$$
BEGIN
IF NOT EXISTS (SELECT FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = lower('entity')
AND column_name = lower('end')
) THEN
ALTER TABLE public.entity
ADD COLUMN "end" TEXT NULL;
ELSE
ALTER TABLE public.entity
ALTER COLUMN "end" TYPE TEXT;
END IF;
END
$$;
I seem to have read some posts where the end keyword can be used as a column if it qouted,
but this still fails?
The error message i get is :
MessageText: syntax error at or near "end"
Why?

Related

Redshift Alter table if not exists

I'm trying add a new field in a redshift table. But I want to add only if this field doesn't exists.
I tried wrapping it with IF NOT EXISTS. But I got following error:
Amazon](500310) Invalid operation: syntax error at or near "IF" Position: 5;
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'schema_name' and table_name='table_name' and column_name='new_field') THEN
ALTER TABLE schema_name.table_name
ADD new_field INT;
END IF;
COMMIT;
I'm not sure if I'm correctly using "IF NOT EXISTS" statement inside the BEGIN block.
Can someone please help me?
Thanks in advance!
It could be better to handle it using EXCEPTION
BEGIN
ALTER TABLE
<table_name> ADD COLUMN <column_name> <column_type>;
EXCEPTION
WHEN duplicate_column
THEN RAISE NOTICE 'column <column_name> already exists in <table_name>.';
END;
The Answer by Yauheni Khvainitski is not completely wrong. But you do have to use a SP and the only option Redshit has (at this point is to have "EXCEPTION WHEN OTHER"). An example:
CREATE OR REPLACE PROCEDURE change_column_to_big_int_TABLE_NAME_X(column_name varchar(200)) AS
$$
DECLARE
new_column_name VARCHAR;
BEGIN
SELECT INTO new_column_name (table_name)||'_new';
-- RAISE INFO 'new_table_name = % table_name = %',new_column_name, table_name;
ALTER TABLE TABLE_NAME_X ADD COLUMN "(new_column_name)" bigint;
EXCEPTION WHEN OTHERS
THEN RAISE NOTICE 'column already exists on table';
END;
$$
LANGUAGE plpgsql;
CALL change_column_to_big_int_TABLE_NAME_X('COLUMN_Y');
Some links from AWS on:
trapping errors: https://docs.aws.amazon.com/redshift/latest/dg/stored-procedure-trapping-errors.html
CREATE PROCEDURE: https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_PROCEDURE.html
Also please notice that this is valid at this point in time. Redshift seems to be always evolving.
The issue I think is that AWS Redshift does not support the IF statement, but instead uses CASE statements. The CASE statements are very similar to IF the way they implement them. But I admit, I prefer the IF statements.

Executing a PostgreSQL query with an EXCEPTION results in two different ERROR messages

I have an PostgreSQL query that includes a transaction and an exception if a column is duplicated:
BEGIN;
ALTER TABLE "public"."cars"
ADD COLUMN "top_speed" text;
EXCEPTION WHEN duplicate_column THEN NOTHING;
ROLLBACK;
In this query I am trying to add a column that already exists (playing a little bit with exceptions) and if it does then the query shall just ignore it. At the moment I am not really sure if the exception-code I am using is the right (couldn't find a site where they are described; only found this)
My Problem is if I execute this query I get the error-message:
ERROR: column "top_speed" of relation "cars" already exists
And if I execute it a second time the error-message changes to:
ERROR: current transaction is aborted, commands ignored until end of transaction block
Try an anonymous code block. As Laurenz mentioned, you were mixing PL/pgSQL and SQL commands.
Sample table
CREATE TABLE t (f1 TEXT);
Anonymous code block
DO $$
BEGIN
IF (SELECT count(column_name) FROM information_schema.columns
WHERE table_schema = 'public' AND
table_name = 't' AND
column_name = 'f2') = 0 THEN
ALTER TABLE public.t ADD COLUMN "f2" text;
END IF;
END$$;
After execution you have your new column. If the column already exists, it will do nothing.
SELECT * FROM t;
f1 | f2
----+----
0 Zeilen
In PostgreSQL 9.6+ you can use IF NOT EXISTS to check if a given column already exists in the table before creating it:
ALTER TABLE t ADD COLUMN IF NOT EXISTS f2 TEXT;
Code at db<>fiddle

PostgreSQL truncate existing field and altering to add character limit

I am altering my existing table that is already filled with columns. In my table 'section', I want to set a character limit on the column "name", specifically type VARCHAR(60). However, there has not been a character limit before, and I would like to truncate any existing fields in the name column so that it now matches this restriction before my ALTER script.
I'm still getting several error messages, including in my LEFT statement, which is what I'm using to truncate the string in the "name" column. The LEFT statement is upset how I'm declaring the string to be truncated, whether I put the parameters in parenthesis or not. This is where I'm at so far:
DO $$
DECLARE
_name text;
_id uuid;
BEGIN
FOR _name, _id IN SELECT (name, id) FROM %SCHEMA%.section
LOOP
IF (_name > 60)
THEN
SET name = LEFT (_name, 60) WHERE id = _id;
END IF;
END LOOP;
RETURN NEW;
END $$;
Once I have this done, I know my ALTER script is very simple:
ALTER TABLE IF EXISTS %SCHEMA%.section ALTER COLUMN name TYPE VARCHAR(60);
You can also make use of the the USING syntax to ALTER TABLE. This allows you to do it as part of the ALTER, rather than as two separate commands.
ALTER TABLE myschema.mytable
ALTER COLUMN mycolumn
TYPE VARCHAR(60)
USING LEFT(mycolumn, 60);
https://www.postgresql.org/docs/9.6/static/sql-altertable.html
use an update query, like this:
UPDATE myschema.mytable
SET name = LEFT(mytable.name, 60)
WHERE LENGTH(mytable.name) > 60

oracle reentrant alter table

I have an SQL script to execute multiple times (must be reentrant).
One of the script line is
alter table MATABLE modify (MADATA null);
This commands works well when the 'not null' constraint for column MADATA of table MATABLE is effectively removed. But the second time, I got an error, example:
Erreur SQL : ORA-01451: colonne à modifier en non renseignée (NULL) ne peut être passée à NULL
01451. 00000 - "column to be modified to NULL cannot be modified to NULL"
That's because the constraint was already removed by the first execution and no more exist.
How to execute this same script without error ?
maybe through PL/SQL Script ?
You can use the data dictionary view user_tab_cols to check the table before doing the update.
declare
lCount number;
begin
select count(*) into lCount from user_tab_cols
where table_name = 'MATABLE'
and column_name = 'MADATA'
and nullable = 'N';
if (lCount = 1) then
execute immediate 'alter table MATABLE modify (MADATA null)';
end if;
end;
Note that user_tab_cols only contains the information about tables in the same schema as the logged on user. If you are modifying tables of another user, you can user all_tab_cols or dba_tab_cols.
Another option would be to use an exception handler and just throw away the exception, like this:
begin
execute immediate 'alter table MATABLE modify (MADATA null)';
exception
when others then
null;
end;
It is normal behavior.
It can happen in two scenarios :
1) If your field column is a constraint
2) if you've already defined the field column as allowing NULL values.

DB2: How do I find if a column is present in a table or list of tables?

Im using a DB2 Database. What would be a suitable SQL query to find out if a column is exists in a table or list of tables?
e.g
if "column_name" is found in "table name" or [list of table names]
return true or the name of tables that have that column.
Many thanks.
Tested on DB2 z/OS 9.1 and LUW 9.7:
SELECT STRIP(TBCREATOR) || '.' || STRIP(TBNAME)
FROM SYSIBM.SYSCOLUMNS
WHERE NAME = 'your_col'
AND TBNAME IN ('list', 'of', 'tables')
If you only want results from a specific schema you might add AND TBCREATOR = 'your_schema' to the end of the query.
Use SYSCAT.COLUMNS catalog view:
SELECT TABNAME
FROM SYSCAT.COLUMNS
WHERE
TABNAME IN ('table name 1', 'table name 2') AND
COLNAME = 'column_name';
Another way to do this is with error handling:
declare v_sql varchar(1000);
declare col_missing integer default 0;
declare col_does_not_exist condition for sqlstate '42703';
declare continue handler for col_does_not_exist set col_missing = 1;
set v_sql = 'select table.foo from table';
execute immediate v_sql;
if col_missing = 1 then
--Do something if column foo doesn't exist.
end if;
This method will work on session tables, and you can also use it on an object even if you don't know whether it is a table, view, alias, etc.
It is important to specify table.foo rather than just the column name, as otherwise the existence of another object (such as a variable) called foo would break the test.
This continue handler will mask any other errors for columns missing within the scope, so it is best to limit the scope to just the test you want to do.