Alter all tables in database - mysql

I would like to run a "Alter Table" on ALL the tables in my SQL databse:
ALTER TABLE test ADD CONSTRAINT [COLLUM_NAME] DEFAULT ((0)) FOR [COLLUM_NAME]
I know how to get all of the existing tables from the database:
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
or
USE DATABASE_NAME
GO
SELECT name
FROM sys.Tables
GO
But I don’t know how to combine these two.
In my database (50+ tables) all of the tables have 1 row in common.
and I would like to set a default value to all of these rows.

You can try to generate a command and execute it after.
You can do something like this:
SELECT CONCAT("Alter Table `", TABLE_SCHEMA,"`.`", TABLE_NAME, "` this is my default value change on the column") as MySQLCMD
FROM TABLES
And execute the retrieving.

If this is a one-off process that doesn't need to be automated then you could probably do worse than running something like the following and just copy/pasting the output:
select 'alter table ' + t.name + ' add constraint ' + c.name + ' default ((0)) for ' + c.name
from sysobjects t join syscolumns c on c.id = t.id
where t.xtype = 'U'

If u want use INFORMATION_SCHEMA
SELECT 'ALTER TABLE ' +t.TABLE_NAME+ ' ADD CONSTRAINT '
+c.COLUMN_NAME +' DEFAULT ((0)) FOR '+c.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLES t
INNER JOIN INFORMATION_SCHEMA.COLUMNS c on t.TABLE_NAME=c.TABLE_NAME
WHERE TABLE_TYPE = 'BASE TABLE'

set the 'COLUMN NAME' and execute, it will add a default constraint to setted column.
DECLARE #sql NVARCHAR(MAX) ;
DECLARE #LINEBREAK AS VARCHAR(2)
SET #LINEBREAK = CHAR(13) + CHAR(10)
SELECT #sql = COALESCE(#sql + ';' + #LINEBREAK, '') + 'ALTER TABLE '
+ QUOTENAME([TABLES].TABLE_NAME) + ' ADD CONSTRAINT ' + QUOTENAME([COLUMNS].COLUMN_NAME)
+ ' DEFAULT ((0)) FOR ' + QUOTENAME([COLUMNS].COLUMN_NAME)
FROM INFORMATION_SCHEMA.TABLES [TABLES]
INNER JOIN INFORMATION_SCHEMA.COLUMNS AS [COLUMNS] ON [TABLES].TABLE_NAME = [COLUMNS].TABLE_NAME
WHERE TABLE_TYPE = 'BASE TABLE'
AND [COLUMNS].[COLUMN_NAME] = 'COLUMN NAME'
PRINT #sql
EXEC sp_executesql #sql

My preferred way is to write a SP for this. I have some of these utility SPs in my databases and I alter them as needed to update things. Here's an example that changes the collation. You can see that by modifying the SET #S=... statement you can do any table alteration you like.
DECLARE table_name VARCHAR(255);
DECLARE end_of_tables INT DEFAULT 0;
DECLARE num_tables INT DEFAULT 0;
DECLARE cur CURSOR FOR
SELECT t.table_name
FROM information_schema.tables t
WHERE t.table_schema = DATABASE() AND t.table_type='BASE TABLE';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET end_of_tables = 1;
OPEN cur;
tables_loop: LOOP
FETCH cur INTO table_name;
IF end_of_tables = 1 THEN
LEAVE tables_loop;
END IF;
SET num_tables = num_tables + 1;
SET #s = CONCAT('ALTER TABLE ' , table_name , ' CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci');
PREPARE stmt FROM #s;
EXECUTE stmt;
END LOOP;
CLOSE cur;

Related

Single mysql Query: To make NULL value of tables & there column's in database

Is this possible with single query we can make all Columns and rows NULL or Zero(0) as its value ?
I have tried but failed to do with 2 3 tables in a Database; to make them NULL.
Perhaps this is what you want or not. I don't understand why you would want to set column values in existing rows to all NULL or 0. Wouldn't it be better just to empty the table, so there are no rows? Then you can add new rows that you want.
To empty a table efficiently, use truncate:
truncate table t;
If you want to set all columns in a table to value, just use an update and list all the columns:
update t
set col1 = null,
col2 = null,
. . .;
However, I don't see why this would be useful.
To update multiple tables in mysql you can use this:
UPDATE table1 , table2 SET table1.column = 0 , table2.column =0
If you don't know the fields you can generate an query to get all the sub-queries that you need
SELECT CONCAT("UPDATE `", TABLE_SCHEMA,"`.`", TABLE_NAME, "` SET `",COLUMN_NAME,"` = 0 ") AS MySQLCMD FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = "you_db_name_here"
now you have all the queries to 0 all the columns in all the tables in database, so now what you can use PREPARE EXECUTE
SET #query :="";
SELECT #query := CONCAT("UPDATE `", TABLE_SCHEMA,"`.`", TABLE_NAME, "` SET `",COLUMN_NAME,"` = 0 ") AS MySQLCMD FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = "you_db_name_here";
PREPARE stmt FROM #query;
EXECUTE stmt;
This will not work if you have primary keys, we need to skip them and the final result will look like this
SET #query :="";
SELECT #query := CONCAT("UPDATE `", C.TABLE_SCHEMA,"`.`", C.TABLE_NAME, "` SET `",C.COLUMN_NAME,"` = '' ") AS MySQLCMD from information_Schema.Columns C LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE U ON C.COLUMN_NAME = U.COLUMN_NAME WHERE C.TABLE_SCHEMA = "you_db_name_here" AND U.CONSTRAINT_NAME is NULL;
PREPARE stmt FROM #query;
EXECUTE stmt;
$sql="SELECT CONCAT('UPDATE ', TABLE_SCHEMA,'.', TABLE_NAME, ' SET ',COLUMN_NAME,' = 0;') AS MySQLCMD FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'DATABASE_NAME' ";
$result=$conn->query($sql);
if($result->num_rows> 0){
while($row=$result->fetch_assoc()){
$exe=$conn->query($row['MySQLCMD']);
}
}
Here's the Answer for what i need. Thanks alot for all your precious suggestions. And special thanks to : angel.bonev

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;

Cursor is becoming an never ending loop

I want to create an SP to generate the metadata for all tables using cursors in SQL. Following is the code I have tried. but its becoming a never ending loop and same data is repeated. Thanks in advance.
--SELECT * FROM information_schema.columns
ALTER PROCEDURE p1
AS
SET NOCOUNT ON;
DECLARE #id INT
, #tablename VARCHAR(100)
, #columnname VARCHAR(100)
, #datatype VARCHAR(100)
, #isnullable VARCHAR(100)
BEGIN
DECLARE CURSOR_1 CURSOR FOR
SELECT TABLE_NAME
, COLUMN_NAME
, DATA_TYPE
, IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Employee' -- group BY table_name
OPEN CURSOR_1
FETCH NEXT FROM CURSOR_1 INTO
#tablename,
#columnname,
#datatype,
#isnullable
WHILE ##fetch_status = 0
BEGIN
INSERT INTO table_schema_detail (TABLE_NAME, COLUMN_NAME, DATA_TYPE, isnullable)
VALUES (#tablename, #columnname, #datatype, #isnullable)
END
FETCH NEXT FROM CURSOR_1 INTO
#tablename,
#columnname,
#datatype,
#isnullable
CLOSE CURSOR_1
DEALLOCATE CURSOR_1
SET NOCOUNT OFF;
END
GO
I don't really understand why you need to store this information on a table, since it's already available on the system views (and if you still need to store this data, why are you using a cursor?). If, like your comment says, you need to store data from 3 tables, then you could simply do:
INSERT INTO table_schema_detail(table_name,column_name,data_type,isnullable)
SELECT table_name, column_name, data_type, is_nullable
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name IN ('Employee','OtherTable1','OtherTable2')
But again, I don't see the point. At least you could store the date when this was done:
INSERT INTO table_schema_detail(table_name,column_name,data_type,isnullable,DateInserted)
SELECT table_name, column_name, data_type, is_nullable, GETDATE()
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name IN ('Employee','OtherTable1','OtherTable2')
look where you have that end statement
insert INTO table_schema_detail(table_name,column_name,data_type,isnullable) VALUES(#tablename,#columnname,#datatype,#isnullable)
end
Suspect it never gets to this line
FETCH NEXT FROM CURSOR_1 into
And agree with other comments on is a cursor the proper approach but this is an answer to the question as stated.
I think get meta-data from sys.columns more preferable (in your case, cursor is not necessary):
INSERT INTO dbo.table_schema_detail
(
TABLE_NAME
, COLUMN_NAME
, DATA_TYPE
, IS_NULLABLE
)
SELECT
SCHEMA_NAME(o.[schema_id]) + '.' + o.name
, c.name
, TYPE_NAME(c.system_type_id)
, c.is_nullable
FROM sys.columns c
JOIN sys.objects o ON c.[object_id] = o.[object_id]
WHERE SCHEMA_NAME(o.[schema_id]) + '.' + o.name = 'dbo.Employee'
AND o.[type] = 'U'

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..

Convert T-SQL to MySQL

Is there an easy way to convert Transact-SQL to MySQL?
I am attempting to convert a database archive of stock ticker symbols and company names.
The short answer: NO
The medium answer: MAYBE
The long answer: That depends on what's in your TSQL and how much time and effort you want to put into it.
TSQL is not a subset of MySQL's dialect. So there exists some TSQL for which there is no MySQL conversion. However, the overlap between the two languages is pretty significant, and to a certain degree the conversion is just a matter of syntax.
This isn't a new problem, and some people have tried to tackle it. A quick google search for "tsql to mysql" yields some promising results, notably this project here, which attempts to convert stored procedures from TSQL to MySQL:
http://sourceforge.net/projects/tsql2mysql/
This probably won't solve your problem completely, but it's at least a start.
This website converts to/from many sql database versions:
http://www.sqlines.com/online
TSQL, MySql, Oracle, DB2, Sybase, Informix, Hive, MariaDB, PostgreSQL, RedShift, TeraData, Greenplum, Netezza
Are the others say, it depends how long your particular piece of string is.
But, I would suggest that you do NOT want to convert Transact-SQL to MySQL.
If you think about it, I think that you will find that you want to convert it to ODBC.
And then next year, when the company wants you to move it to Oracle, or Access ...
I've just achieved a tsql script.
My solution is :
export table informations (schema pk)
export table data
export FK
I'm not very proud of my code, but it worked for me.
4 files wich are in the same folder:
Batch wich call sqlcmd
#echo off
set host= (local)
set schema=database
set user=user
set pass=pass
cd %cd%
rem tables
SQLCMD -S %host% -d %schema% -U %user% -P %pass% -s "" -h-1 -W -i "%CD%\mysql_export_table.sql" -o "%CD%\%schema%_tables.sql"
rem data
SQLCMD -S %host% -d %schema% -U %user% -P %pass% -s "" -h-1 -W -i "%CD%\mysql_export_data.sql" -o "%CD%\%schema%_data.sql"
rem fk
SQLCMD -S %host% -d %schema% -U %user% -P %pass% -s "" -h-1 -W -i "%CD%\mysql_export_fk.sql" -o "%CD%\%schema%_fk.sql"
then tsql script to export table schema mysql_export_table.sql
SET NOCOUNT ON;
SET QUOTED_IDENTIFIER ON;
DECLARE #table_name as varchar(max)
DECLARE view_cursor CURSOR FOR
SELECT Table_name FROM information_schema.tables where TABLE_TYPE = 'BASE TABLE' and table_name not like 'sys%'
OPEN view_cursor
FETCH NEXT FROM view_cursor
INTO #table_name
WHILE ##FETCH_STATUS = 0
BEGIN
select ''
select '/*** TABLE '+#table_name+' ***/ '
select 'DROP TABLE IF EXISTS ' + QUOTENAME(#table_name, '`') + ';'
select ''
select 'CREATE TABLE ' + QUOTENAME(#table_name, '`') + ' ('
-- column declaration
select
CHAR(9)
+ QUOTENAME(Column_Name, '`') + ' ' +
DATA_TYPE
+
coalesce( '(' + cast(coalesce(replace(CHARACTER_MAXIMUM_LENGTH, -1, 2500), null) as varchar) + ')', '')
+ ' ' +
case IS_NULLABLE WHEN 'NO' then 'NOT ' else '' end + 'NULL'
+ ' ' +
case when COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1 then 'AUTO_INCREMENT' else '' end
--coalesce( 'DEFAULT ' + replace(replace(replace(COLUMN_DEFAULT, '(', ''), ')', ''), 'getdate', null), '')
+','
FROM information_schema.COLUMNS where TABLE_NAME = #table_name
-- PK
select coalesce('PRIMARY KEY (' +STUFF((
SELECT distinct ', ' + QUOTENAME(Col.Column_Name,'`') from
INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab inner join
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col on Col.Constraint_Name = Tab.Constraint_Name AND Col.Table_Name = Tab.Table_Name
WHERE
Constraint_Type = 'PRIMARY KEY '
AND Col.Table_Name = #table_name
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') , 1, 1, '')+ ')', '')
select ') Engine InnoDB;'
FETCH NEXT FROM view_cursor
INTO #table_name
END
CLOSE view_cursor;
DEALLOCATE view_cursor;
then script for data mysql_export_data.sql
SET NOCOUNT ON;
SET QUOTED_IDENTIFIER ON;
DECLARE #table_name as varchar(max)
declare #column_names as varchar(max)
DECLARE view_cursor CURSOR FOR
SELECT Table_name FROM information_schema.tables where TABLE_TYPE = 'BASE TABLE' and table_name not like 'sys%'
OPEN view_cursor
FETCH NEXT FROM view_cursor
INTO #table_name
WHILE ##FETCH_STATUS = 0
BEGIN
select ''
select '/*** TABLE '+#table_name+' ***/ '
select #column_names = STUFF(( SELECT ', ' + QUOTENAME(Column_Name, '`') from INFORMATION_SCHEMA.COLUMNS WHERE Table_Name = #table_name ORDER BY ORDINAL_POSITION FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') , 1, 1, '')
select 'REPLACE INTO '+ QUOTENAME(#table_name, '`') +'('+ #column_names+ ') VALUES '
select #column_names = 'SELECT DISTINCT ''('+ STUFF(( SELECT ', '','''''' + coalesce(replace(cast(' + QUOTENAME(Column_Name) +' as varchar(200)), '''''''',''''), '''') + ''''''''' from INFORMATION_SCHEMA.COLUMNS WHERE Table_Name = #table_name ORDER BY ORDINAL_POSITION FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') , 1, 4, '') + '+''),'' FROM ' + QUOTENAME(#table_name)
exec (#column_names)
FETCH NEXT FROM view_cursor
INTO #table_name
END
CLOSE view_cursor;
DEALLOCATE view_cursor;
Finally FK script
SET NOCOUNT ON;
SET QUOTED_IDENTIFIER ON;
-- FK
-- foreign keys
SELECT
'ALTER TABLE',
' '+ QUOTENAME(OBJECT_NAME(fkcol.[object_id]), '`'),
--ADD CONSTRAINT `recherche_ibfk_1` FOREIGN KEY (`notaire_compte_id`) REFERENCES `notaire_compte` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
' ADD CONSTRAINT',
' ' + QUOTENAME(fk.name, '`'),
' FOREIGN KEY',
' (' + QUOTENAME(fkcol.name, '`') +')',
' REFERENCES',
' ' + QUOTENAME(OBJECT_NAME(pkcol.[object_id]), '`'),
' (' + QUOTENAME(pkcol.name, '`') + ');',
CHAR(13)
FROM sys.foreign_keys AS fk
INNER JOIN sys.foreign_key_columns AS fkc
ON fk.[object_id] = fkc.constraint_object_id
INNER JOIN sys.columns AS fkcol
ON fkc.parent_object_id = fkcol.[object_id]
AND fkc.parent_column_id = fkcol.column_id
INNER JOIN sys.columns AS pkcol
ON fkc.referenced_object_id = pkcol.[object_id]
AND fkc.referenced_column_id = pkcol.column_id
ORDER BY fkc.constraint_column_id;
I know, i know... it's very ugly ...
The goal of this script is not to convert TSQL to Mysql but to export database from MSSQL to Mysql
On the table result you'll have to execute a regex replace (notepad++)
replace ",\r\n\r\n)" by "\r\n\r\n)"
On the data result replace ",\r\n\r\n/" by ";\r\n\r\n/"
Execution order : Table -> Data -> FK
How about using SQL Server Linked Servers ? You can SELECT, INSERT, UPDATE and DELETE data from MySQL using TSQL