IF NOT EXISTS SyntaxError in MySQL - mysql

I'm trying to write a kind of update SQL to add new columns if they don't already exist.
I've already tried a few things, but nothing works.
If I try an IF NOT EXISTS I always get a syntax error that I can't understand.
IF NOT EXISTS(
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'nutzer'AND table_schema = 'restdb' AND column_name = 'api_nutzer')
THEN
ALTER TABLE `nutzer` ADD `api_nutzer` TINYINT;
END IF;
[SQL] IF NOT EXISTS( SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'nutzer'
AND table_schema = 'restdb'
AND column_name = 'api_nutzer') THEN
ALTER TABLE `nutzer` ADD `api_nutzer` TINYINT;
[Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IF NOT EXISTS( SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
' at line 1
If I execute the SELECT directly, I get a result
Does anyone have an idea or know where my mistake is?
I use MySQL Server Version 8.0.22

I have understood that the Exists clause can be used in the WHERE section
SELECT column1 FROM t1 WHERE EXISTS (SELECT * FROM t2);
try to reconstruct your query for captured if the row exists
for example
<i>if( /*begin extra condition*/ Select 1 where exists
(SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'nutzer'
AND table_schema = 'restdb'
AND column_name = 'api_nutzer') = 1 /*end extra condition*/) then
ALTER TABLE `nutzer` ADD `api_nutzer` TINYINT;</i>

Thanks for your help i get an solutuion for my Problem.
DROP PROCEDURE IF EXISTS addCol;
CREATE PROCEDURE addCol(
IN tabelle VarChar(255),
IN spalte VarChar(255),
IN type VarChar(255)
)
BEGIN
IF NOT EXISTS (
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = tabelle
AND TABLE_SCHEMA = 'restdb'
AND COLUMN_NAME = spalte
)
THEN
SET #ddl = CONCAT(' alter table ', tabelle ,' ADD ', spalte, ' ', type);
PREPARE STMT FROM #ddl;
EXECUTE STMT;
END IF;
END

Related

IF Exists then update in mysql

New to MySQL, need help in translating the next query to MySQL
If exists (select * from INFORMATION_SCHEMA.COLUMNS where table_name= 'MyTable' and column_name = 'MyColumn')
begin
update MyTable set MyColumn='' where Code=21
end;
Based on the comments posted on your question, here is a code snippet that should answer your need. It works by first checking if the column exists in INFORMATION_SCHEMA, and then dynamically building a SQL query that is prepared, then executed. It the column does not exists, a dummy query is executed instead of the UPDATE. I tested it in this db fiddlde.
SET #dbname = DATABASE();
SET #tablename = "my_table";
SET #columnname = "my_column";
-- check if the column exists
SELECT COUNT(*) INTO #cnt
FROM INFORMATION_SCHEMA.COLUMNS
WHERE
(table_name = #tablename)
AND (table_schema = #dbname)
AND (column_name = #columnname)
;
-- build a dynamic SQL statement
SET #preparedStatement = (SELECT IF(
#cnt > 0,
CONCAT("UPDATE ", #tablename, " SET ", #columnname, " = '' WHERE my_code = 21;"),
"SELECT 1"
));
-- run the statement
PREPARE updateIfExists FROM #preparedStatement;
EXECUTE updateIfExists;
DEALLOCATE PREPARE updateIfExists;

Flyway | MariaDb - Unable to execute conditional block

I want to add a not null column to a table with existing data. My toolset includes MariaDb and flyway. Here's what I am doing
IF NOT EXISTS(SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'MY_DATA_TABLE'
AND table_schema = '${schemaName}'
AND column_name = 'NewColumnName'
) THEN
ALTER TABLE MY_DATA_TABLE ADD COLUMN 'NewColumnName' INT;
SELECT ID INTO #val FROM MASTER_TABLE WHERE lower(Name) = 'XYZ';
UPDATE MY_DATA_TABLE SET NewColumnName = #val;
ALTER TABLE MY_DATA_TABLE MODIFY COLUMN 'NewColumnName' INT NOT NULL;
END IF;
Doing mvn flyway:migrate gives me this error
[ERROR] SQL State : 42000
[ERROR] Error Code : 1064
[ERROR] Message : You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''NewColumnName'
INT' at line 7
I even tried placing some running select statement inside, but the error remains the same. Please suggest some workaround. Please also recommend if there's another way to achieve the objective.
Thanks!
I suspect the issue is with quoting the column name. Try executing the SQL interactively and see if you get the same error. Then try and get it working successfully. In a related question the answer was to try no quotes around column names or to escape them with back ticks.
Here's how I ended up to meet the desired.
DROP PROCEDURE IF EXISTS `proc_UpdateMyColumn`;
DELIMITER //
CREATE PROCEDURE `proc_UpdateMyColumn`
(
)
BEGIN
DECLARE valueToSet INT;
IF NOT EXISTS (SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'MY_DATA_TABLE'
AND table_schema = '${schemaName}'
AND column_name = 'NewColumnName'
) THEN
ALTER TABLE MY_DATA_TABLE ADD COLUMN NewColumnName INT;
SELECT ID INTO valueToSet FROM MASTER_TABLE WHERE lower(Name) = 'XYZ';
UPDATE MY_DATA_TABLE SET NewColumnName = valueToSet;
ALTER TABLE MY_DATA_TABLE MODIFY COLUMN NewColumnName INT NOT NULL;
END IF;
END;
DELIMITER;
CALL `proc_UpdateMyColumn`();
DELIMITER;

How do I check whether column exists in the table?

I need to check whether mytable table is containing mycolumn column? Here is my query:
SELECT CASE WHEN EXISTS (SHOW COLUMNS FROM mytable LIKE mycolumn) THEN 1 ELSE 0 END;
But it doesn't work and throws this error-message:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use
near 'SHOW COLUMNS FROM mytable LIKE mycolumn) THEN 1 ELSE 0 END at line 1
What's wrong and how can I fix it?
You can use the following as an if
IF EXISTS(
select * from
INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME ='SOMETABLE' AND
COLUMN_NAME = 'SOMECOLUMN')
)
BEGIN
-- do stuff
END
GO
Alternatively as a case
SELECT CASE WHEN EXISTS(
select * from
INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME ='TABLE_NAME' AND
COLUMN_NAME = 'COLUMN_NAME')
Then 1 Else 0 End;
Try this instead
SELECT CASE WHEN EXISTS (
SELECT * FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'db_name'
AND TABLE_NAME = 'table_name'
AND COLUMN_NAME = 'column_name')
then 1
else 0
end;
If you need to pass the Table and Column name dynamically , please use this.
DECLARE #Table Varchar(100)
DECLARE #Column Varchar(100)
DECLARE #Query nvarchar(max)
SET #Table ='MyTable'
SET #Column ='MyColumn'
SET #Query ='select * from
INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME ='''+#Table+''' AND
COLUMN_NAME IN ('''+#Column+''')'
EXEC (#Query)

MySQL Derterministic migration script

I am currently looking a way to have my database under version control. To achieve so, I wanted to have deterministic procedures that can only be run only once (with corresponding undo).
I have a problem building my first script which is riddled with small bugs.
Here are the 3 main parts :
Condition to execute query (if field doesn't exists)
SELECT *
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'my_database'
AND TABLE_NAME = 'my_table'
AND COLUMN_NAME = 'full_name'
The table alteration:
ALTER TABLE
my_table
ADD full_name VARCHAR(255) NOT NULL;
And finally the data migration
UPDATE candidat dest JOIN candidat src ON dest.id = src.id
SET dest.full_name = CONCAT(src.first_name, ' ', IF(src.middle_name='', '', CONCAT(src.middle_name, ' ')), src.last_name);
I'am trying to make this work in this form:
DELIMITER $$
DROP PROCEDURE IF EXISTS migration_001;
CREATE PROCEDURE migration_001()
BEGIN
IF NOT EXISTS (
SELECT *
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'my_database'
AND TABLE_NAME = 'my_table'
AND COLUMN_NAME = 'full_name')
THEN
ALTER TABLE
my_table
ADD full_name VARCHAR(255) NOT NULL;
UPDATE candidat dest JOIN candidat src ON dest.id = src.id
SET dest.full_name = CONCAT(src.first_name, ' ', IF(src.middle_name='', '', CONCAT(src.middle_name, ' ')), src.last_name);
END IF
END;
$$
Current error I am getting:
1064 : ... right syntax to use near 'CREATE PROCEDURE migration_001() BEGIN IF NOT EXISTS ( SELECT * ' at line 3
Can anyone point me in the right direction for solving this?
BTW I am using 5.5.16-log - MySQL Community Server.
Change the order of
DELIMITER $$
and
DROP PROCEDURE IF EXISTS migration_001;
Currently you are using the wrong delimiter to drop the procedure.

MySQL sorting table by column names

I have already built a table with field names in arbitrary order. I want those field names to be in alphabetical order so that I can use them in my dropdown list. Is it possible with a query?
Select columns from a specific table using INFORMATION_SCHEMA.COLUMNS and sort alphabetically with ORDER BY:
SELECT column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_schema = '[schemaname]'
AND table_name = '[tablename]'
ORDER BY column_name
Note: The following code will alter the specified table and reorder the columns in alphabetical order
This should do the trick. It's a bit messy and lengthy, and you'll have to change the database name and table name, but for this one, the only requirement is that there is a database named "test" and that you are running these commands in it:
Let's create the tables we need:
-- CREATE TESTING TABLE IN A DATABASE NAMED "test"
DROP TABLE IF EXISTS alphabet;
CREATE TABLE alphabet (
d varchar(10) default 'dee' not null
, f varchar(21)
, e tinyint
, b int NOT NULL
, a varchar(1)
, c int default '3'
);
-- USE A COMMAND STORAGE TABLE
DROP TABLE IF EXISTS loadcommands;
CREATE TABLE loadcommands (
id INT NOT NULL AUTO_INCREMENT
, sqlcmd VARCHAR(1000)
, PRIMARY KEY (id)
);
Now let's create the two stored procedures required for this to work:
Separating them since one will be responsible for loading the commands, and including a cursor to immediately work with it isn't plausible (at least for me and my mysql version):
-- PROCEDURE TO LOAD COMMANDS FOR REORDERING
DELIMITER //
CREATE PROCEDURE reorder_loadcommands ()
BEGIN
DECLARE limitoffset INT;
SET #rank = 0;
SET #rankmain = 0;
SET #rankalter = 0;
SELECT COUNT(column_name) INTO limitoffset
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_schema = 'test'
AND table_name = 'alphabet';
INSERT INTO loadcommands (sqlcmd)
SELECT CONCAT(t1.cmd, t2.position) AS commander FROM (
SELECT #rankalter:=#rankalter+1 AS rankalter, CONCAT('ALTER TABLE '
, table_name, ' '
, 'MODIFY COLUMN ', column_name, ' '
, column_type, ' '
, CASE
WHEN character_set_name IS NOT NULL
THEN CONCAT('CHARACTER SET ', character_set_name, ' COLLATE ', collation_name, ' ')
ELSE ' '
END
, CASE
WHEN is_nullable = 'NO' AND column_default IS NULL
THEN 'NOT NULL '
WHEN is_nullable = 'NO' AND column_default IS NOT NULL
THEN CONCAT('DEFAULT \'', column_default, '\' NOT NULL ')
WHEN is_nullable = 'YES' THEN 'DEFAULT NULL '
END
) AS cmd
, column_name AS columnname
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_schema = 'test'
AND table_name = 'alphabet'
ORDER BY columnname
) t1
INNER JOIN (
SELECT #rankmain:=#rankmain+1 AS rownum, position FROM (
SELECT 0 AS rownum, 'FIRST' AS position
, '' AS columnname
UNION
SELECT #rank:=#rank+1 AS rownum, CONCAT('AFTER ', column_name) AS position
, column_name AS columnname
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_schema = 'test'
AND table_name = 'alphabet'
ORDER BY columnname
LIMIT limitoffset
) inner_table
) t2 ON t1.rankalter = t2.rownum
;
END//
DELIMITER ;
If anyone thinks/sees that I'm missing to include any important column attributes in the ALTER command, please hesitate not and mention it! Now to the next procedure. This one just executes the commands following the order of column id from the loadcommands table. :
-- PROCEDURE TO RUN EACH REORDERING COMMAND
DELIMITER //
CREATE PROCEDURE reorder_executecommands ()
BEGIN
DECLARE sqlcommand VARCHAR(1000);
DECLARE isdone INT DEFAULT FALSE;
DECLARE reorderCursor CURSOR FOR
SELECT sqlcmd FROM loadcommands ORDER BY id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET isdone = TRUE;
OPEN reorderCursor;
read_loop:LOOP
FETCH reorderCursor INTO sqlcommand;
IF isdone THEN
LEAVE read_loop;
END IF;
SET #sqlcmd = sqlcommand;
PREPARE stmt FROM #sqlcmd;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP read_loop;
CLOSE reorderCursor;
END//
DELIMITER ;
The SQL is long, so if someone can point out ways (and has tested them) to make this shorter I'd gladly do it, but for now, this at least works on my end. I also didn't need to put dummy data in the alphabet table. Checking the results can be done using the SHOW... command.
The last part:
-- TO TEST; AFTER RUNNING DDL COMMANDS:
SHOW CREATE TABLE alphabet; -- SEE ORIGINAL ORDER
CALL reorder_loadcommands(); -- PREPARE COMMANDS
CALL reorder_executecommands(); -- RUN COMMANDS
SHOW CREATE TABLE alphabet; -- SEE NEW ORDER
Perhaps later on I could make reorder_loadcommands dynamic and accept table and schema parameters, but I guess this is all for now..