How do you drop indexes in a SQL Server 2008 database? This is what I've got so far:
declare #procname varchar(500)
declare cur cursor
for
select name from sysindexes
open cur
fetch next from cur into #procname
while ##FETCH_STATUS=0
begin
exec ('drop index ' + #procname)
fetch next from cur into #procname
end
close cur
deallocate cur
You need to use something like this, because the DROP INDEX statement requires you to specify the table name:
-- define variables for index, schema and table name
DECLARE #indexname sysname
DECLARE #schemaname sysname
DECLARE #tablename sysname
-- declare variable for actual DROP statement
DECLARE #dropstatement NVARCHAR(1000)
-- declare cursor for iterating over all indexes
DECLARE index_cursor CURSOR LOCAL FAST_FORWARD
FOR
SELECT ix.name, t.name, s.name
FROM sys.indexes ix
INNER JOIN sys.tables t ON t.object_id = ix.object_id
INNER JOIN sys.schema s ON t.schema_id = s.schema_id
WHERE t.is_ms_shipped = 0
-- open cursor
OPEN index_cursor
-- get first index, table and schema name
FETCH NEXT FROM index_cursor INTO #indexname, #tablename, #schemaname
WHILE ##FETCH_STATUS = 0
BEGIN
-- define the DROP statement
SET #dropstatement = N'DROP INDEX ' + QUOTENAME(#indexname) +
N' ON ' QUOTENAME(#schemaname) + N'.' +
QUOTENAME(#tablename)
-- execute the DROP statement
EXEC sp_executesql #dropstatement
-- get next index, table and schema name
FETCH NEXT FROM index_cursor INTO #indexname, #tablename, #schemaname
END
CLOSE index_cursor
DEALLOCATE index_cursor
Related
Using MySQL 8.0, have written stored procedure (SP) having Dynamic SQL and result is collected in a View. However, when SP is executed, it just returns column names not the column values. SP source code is given below.
drop procedure if exists dynamic_cursor;
delimiter //
CREATE PROCEDURE dynamic_cursor (IN table_name VARCHAR(40),
IN key_name VARCHAR(40),
IN column_name VARCHAR(40),
IN before_date DATETIME,
IN curr_key VARCHAR(40))
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE v_key_name VARCHAR(40);
DECLARE v_column_name varchar(50);
DECLARE out1 VARCHAR(100);
DECLARE out2 VARCHAR(100);
DECLARE cur CURSOR for( SELECT key_name, column_name from past_shpt_view);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DROP VIEW IF EXISTS past_shpt_view;
SET #sqlstr = "CREATE VIEW past_shpt_view as ";
SET #sqlstr = CONCAT(#sqlstr , " SELECT ", key_name,",", column_name);
SET #sqlstr = CONCAT(#sqlstr , " FROM ", table_name);
set #sqlstr = concat(#sqlstr, " where rec_cre_dt_utc < '");
set #sqlstr = concat(#sqlstr, before_date,"'");
set #sqlstr = concat(#sqlstr, " and shipment_num = '");
set #sqlstr = concat(#sqlstr, curr_key, "'");
set #sqlstr = concat(#sqlstr,' order by rec_cre_dt_utc desc LIMIT 1');
PREPARE stmt FROM #sqlstr;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
OPEN cur;
FETCH cur INTO v_key_name, v_column_name;
SELECT v_key_name, v_column_name;
CLOSE cur;
END;
//
delimiter ;
Any idea what could be the issue. Have spent a whole of time on this. Please help.
I need to get the result table with there fields
- table_name, min_date, max_date
Here is my query, which I should execute for all tables
SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM testTable
GROUP BY short_date
HAVING COUNT(*) > 1) as Duplicates
Then I found out how to get all table names
I do it in this way
SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%'
But I don't know how to execute it for all table and fill in the result in a new table.
I tried to do it in this way
DECLARE #DB_Name varchar(50)
DECLARE #Command varchar(100);
DECLARE database_cursor CURSOR FOR
SELECT name
FROM (SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%') as TableNames
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #DB_Name
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #Command = 'SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM ' + #DB_Name + '
WHERE type = ''test''
GROUP BY short_date, type, value
HAVING COUNT(*) > 1) as Duplicates'
EXEC sp_executesql #Command
FETCH NEXT FROM database_cursor INTO #DB_Name
END
CLOSE database_cursor
DEALLOCATE database_cursor
But I got this error
Syntax error or access violation: 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 'DECLARE #DB_Name varchar(50) DECLARE
#Command varchar(100)' at line 1
UPD
CREATE PROCEDURE GetData()
BEGIN
DECLARE #DB_Name varchar(50), #Command varchar(100);
DECLARE database_cursor CURSOR FOR
SELECT name
FROM (SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%_') as TableNames
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #DB_Name
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #Command = 'SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM ' + #DB_Name + '
WHERE type = ''test''
GROUP BY short_date, type, value
HAVING COUNT(*) > 1) as Duplicates'
EXEC sp_executesql #Command
FETCH NEXT FROM database_cursor INTO #DB_Name
END;
CLOSE database_cursor
DEALLOCATE database_cursor
END;
CALL GetData()
Add DELIMITER $$ at the start; add DELIMITER ; after END.
Get rid of declaring Command. Instead use #command, which does not need to be declared.
Add SELECT #command; after the SELECT #command := ...; so that we can do some debugging.
The CLOSE and DEALLOCATE statements need ; to terminate them.
Test for running out of rows to FETCH.
You really need to look at a number of examples of Stored procedures, especially those with cursors.
Update
Ugh, I did not spot even half the syntax errors. This might work (I can't tell because I don't have your particular tables or columns.):
DROP PROCEDURE IF EXISTS so42856538;
DELIMITER $$
CREATE PROCEDURE so42856538()
LANGUAGE SQL
MODIFIES SQL DATA
SQL SECURITY INVOKER
BEGIN
DECLARE _TableName varchar(64);
DECLARE _done INT DEFAULT FALSE;
DECLARE database_cursor CURSOR FOR
SELECT TABLE_NAME
FROM `information_schema`.`TABLES`
WHERE `TABLE_SCHEMA` = 'test'
AND `TABLE_NAME` LIKE 'test%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET _done = TRUE;
OPEN database_cursor;
curs_loop: LOOP
FETCH NEXT FROM database_cursor INTO _TableName;
IF _done THEN LEAVE curs_loop; END IF;
SET #Command := CONCAT(
'SELECT MIN(short_date) as FirstDuplicatedDate,
MAX(short_date) as LastDuplicatedDate
FROM ( SELECT short_date, type, value, count(*) as cnt
FROM ', _TableName, '
WHERE type = "test"
GROUP BY short_date, type, value
HAVING COUNT(*) > 1 ) as Duplicates'
);
SELECT _TableName, #command; -- Debugging (remove if it is clutter)
PREPARE _sql FROM #command;
EXECUTE _sql;
DEALLOCATE PREPARE _sql;
END LOOP;
CLOSE database_cursor;
END $$
DELIMITER ;
CALL so42856538;
right... you might want to try this.
remove this line and run the query again.
DECLARE #DB_Name varchar(50), #Command varchar(100);
i think in mysql you can just use a variable without declaring it and then cast when necessary.
As far as my knowledge concern this error is due to ,DELIMETER and one more thing that you have to apply cursor properly to iterate whole rowset.Here in below code i had wrote down procedure with CURSOR.Make dynamic query and execute that dynamic query using
PREPARE stmt FROM #VAR_QRY; EXECUTE stmt;
That dynamic query will returns exact output you want.Here i had assuming that you have basic knowledge about trigger,loop and Cursor
Try below code.
Hope this will helps.
DROP PROCEDURE IF EXISTS ITERATEALLTABLE;
DELIMITER $$
CREATE PROCEDURE ITERATEALLTABLE()
BEGIN
DECLARE VAR_TABLE varchar(100);
DECLARE VAR_QRY varchar(100);
DECLARE VAR_FINISHED INT(11) DEFAULT 0;
DECLARE DATABASE_CURSOR CURSOR FOR
SELECT name AS TableNames
FROM (
SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%'
)Z ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET VAR_FINISHED = 1;
OPEN DATABASE_CURSOR;
GET_NEXTRECORD: LOOP
FETCH DATABASE_CURSOR INTO VAR_TABLE;
IF VAR_FINISHED = 1 THEN
LEAVE GET_NEXTRECORD;
END IF;
SET #VAR_QRY = CONCAT("SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM " , VAR_TABLE , " WHERE type = 'test'
GROUP BY short_date, type, value
HAVING COUNT(*) > 1) as Duplicates");
PREPARE stmt FROM #VAR_QRY;
EXECUTE stmt;
END LOOP GET_NEXTRECORD;
CLOSE DATABASE_CURSOR;
END;
CALL ITERATEALLTABLE;
In my MySQL setup I have about a dozen database with hundreds of tables where all id fields are defined with type varchar(20). Per database there are a few thousand of these fields. These fields need to be altered into varchar(36).
In order to make this happen I have created a stored procedure, that:
gets all appropriate schemas;
get the tables of the schemas;
loop through all the columns and when the column type = 'varchar(20) alter the column to varchar(36).
The content of the procedure is available below. But instead of altered column types I get nothing. Meaning there is something wrong. But what is it?
Can you help me out?
DELIMITER $$
DROP PROCEDURE IF EXISTS `get_database`$$
DROP PROCEDURE IF EXISTS `get_table`$$
DROP PROCEDURE IF EXISTS `get_column`$$
DROP PROCEDURE IF EXISTS `alter_column`$$
CREATE PROCEDURE get_database()
BEGIN
DECLARE db_rows INT;
DECLARE dbI INT DEFAULT 1;
DECLARE db_name VARCHAR(255);
DECLARE db_names CURSOR FOR SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME LIKE '%ofb%';
SET #enabled = TRUE;
select FOUND_ROWS() into db_rows;
open db_names;
db_loop: LOOP
if dbI > db_rows THEN
CLOSE db_names;
LEAVE db_loop;
end if;
FETCH db_names INTO db_name;
-- database found
if db_name then
call get_table(db_name);
end if;
SET #dbI = #dbI + 1;
END LOOP db_loop;
END $$
CREATE PROCEDURE get_table(db_name VARCHAR(255))
BEGIN
DECLARE tn_rows INT;
DECLARE tnI INT DEFAULT 1;
DECLARE table_name VARCHAR(255);
DECLARE table_names CURSOR FOR SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = db_name;
SET #enabled = TRUE;
SET tnI = 1;
SET #enabled = TRUE;
select FOUND_ROWS() into tn_rows;
open table_names;
table_loop: LOOP
if tnI > tn_rows THEN
CLOSE table_names;
LEAVE table_loop;
end if;
FETCH table_names INTO table_name;
-- table_name found
if table_name then
call get_column(db_name, table_name);
end if;
SET tnI = tnI + 1;
END LOOP table_loop;
END $$
CREATE PROCEDURE get_column(db_name VARCHAR(255), table_name VARCHAR(255))
BEGIN
DECLARE cn_rows INT;
DECLARE cnI INT DEFAULT 1;
DECLARE column_name VARCHAR(255);
DECLARE column_names
CURSOR FOR SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = db_name and TABLE_SCHEMA = table_name;
SET #enabled = TRUE;
SET cnI = 1;
select FOUND_ROWS() into cn_rows;
open column_names;
column_loop: LOOP
if cnI > nn_rows THEN
CLOSE column_names;
LEAVE column_loop;
end if;
FETCH column_names INTO column_name;
-- column_name found
if column_name then
call alter_column(db_name, table_name, column_name);
end if;
SET cnI = cnI + 1;
END LOOP column_loop;
END $$
CREATE PROCEDURE alter_column(db_name VARCHAR(255), table_name VARCHAR(255), column_name VARCHAR(255))
BEGIN
DECLARE dtype VARCHAR(255);
declare data_type
CURSOR FOR SELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = table_name and TABLE_NAME = table_name AND COLUMN_NAME = column_name;
open data_type;
fetch data_type into dType;
if dType = 'varchar(20)' then
SET #ddl = CONCAT('alter table ', db_name, '.',table_name, ' modify column (', column_name, ' VARCHAR(36))');
PREPARE STMT FROM #ddl;
EXECUTE STMT;
end if;
END $$
DELIMITER ;
Your help is appreciated.
Best regards
I was in need of these procedures, and see some changes I made, that worked:
CREATE PROCEDURE get_database()
BEGIN
DECLARE _table_name VARCHAR(255);
DECLARE finished INTEGER DEFAULT 0;
DECLARE table_names CURSOR FOR
SELECT table_name
FROM INFORMATION_SCHEMA.TABLES WHERE
TABLE_SCHEMA like '%ofb%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
OPEN table_names;
table_loop: LOOP
FETCH table_names INTO _table_name;
IF finished = 1 THEN
CLOSE table_names;
LEAVE table_loop;
END IF;
CALL get_column('%ofb%', _table_name);
END LOOP table_loop;
END
CREATE PROCEDURE get_column(db_name VARCHAR(255), table_name VARCHAR(255))
BEGIN
DECLARE _column_name VARCHAR(255);
DECLARE finished INTEGER DEFAULT 0;
DECLARE column_names CURSOR FOR
SELECT column_name FROM
INFORMATION_SCHEMA.COLUMNS
WHERE table_schema LIKE db_name AND
TABLE_NAME = _table_name AND
DATA_TYPE = "varchar" AND
CHARACTER_MAXIMUM_LENGTH = 20
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
OPEN column_names;
column_loop: LOOP
FETCH column_names INTO _column_name;
IF finished = 1 THEN
CLOSE column_names;
LEAVE column_loop;
END IF;
SET #ddl = CONCAT('ALTER TABLE ', db_name, '.',_table_name, ' MODIFY COLUMN ', _column_name, ' VARCHAR(36) NULL');
PREPARE STMT FROM #ddl;
EXECUTE STMT;
END LOOP column_loop;
END
I need to rename column for all tables in my databse.
I could get list of columns using this query:
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME= <Column Name>;
But how actually I could rename it as simple as possible and do not write
ALTER TABLE <Table Name >RENAME COLUMN <Old name> to <New Name>;
for each table.
I've tried to write a procedure:
DELIMITER $$
DROP PROCEDURE IF EXISTS renameColumn $$
CREATE PROCEDURE renameColumn(IN oldName tinytext, IN newName tinytext)
BEGIN
DECLARE #name VARCHAR(255);
DECLARE exit_loop BOOLEAN;
DECLARE tableName_cursor CURSOR FOR SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME=oldName;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop = TRUE;
OPEN tableName_cursor;
rename_loop: LOOP
FETCH tableName_cursor #name;
ALTER TABLE #name RENAME COLUMN oldName to newName;
IF exit_loop THEN
LEAVE rename_loop;
END IF;
END LOOP rename_loop;
END $$
DELIMITER;
But I have the following error:
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 '#name VARCHAR(255);
DECLARE exit_loop BOOLEAN;
DECLARE ta' at line 3
Could you please help me to resolve this issue
You can try this.
SELECT CONCAT(
'ALTER TABLE ', TABLE_NAME,
' RENAME COLUMN ', COLUMN_NAME,
' NEW_', COLUMN_NAME,
';') AS rename_script
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'your_db'
Try the following solution hope it will help
DECLARE #name VARCHAR(50) -- database name
DECLARE db_cursor CURSOR FOR
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME= 'OldColumn';
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
set #name = #name + '.OldColumn'
EXEC sp_rename #name, 'NewColumn', 'COLUMN';
print(#name)
FETCH NEXT FROM db_cursor INTO #name
END
CLOSE db_cursor
DEALLOCATE db_cursor
I want to run a diagnostic report on our SQL Server 2008 database server.
I am looping through all of the databases, and then for each database, I want to look at each table. But, when I go to look at each table (with tbl_cursor), it always picks up the tables in the database 'master'.
I think it's because of my tbl_cursor selection :
SELECT table_name FROM information_schema.tables WHERE table_type = 'base table'
How do I fix this?
Here's the entire code:
SET NOCOUNT ON
DECLARE #table_count INT
DECLARE #db_cursor VARCHAR(100)
DECLARE database_cursor CURSOR FOR
SELECT name FROM sys.databases where name<>N'master'
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #db_cursor
WHILE ##Fetch_status = 0
BEGIN
PRINT #db_cursor
SET #table_count = 0
DECLARE #table_cursor VARCHAR(100)
DECLARE tbl_cursor CURSOR FOR
SELECT table_name FROM information_schema.tables WHERE table_type = 'base table'
OPEN tbl_cursor
FETCH NEXT FROM tbl_cursor INTO #table_cursor
WHILE ##Fetch_status = 0
BEGIN
DECLARE #table_cmd NVARCHAR(255)
SET #table_cmd = N'IF NOT EXISTS( SELECT TOP(1) * FROM ' + #table_cursor + ') PRINT N'' Table ''''' + #table_cursor + ''''' is empty'' '
--PRINT #table_cmd --debug
EXEC sp_executesql #table_cmd
SET #table_count = #table_count + 1
FETCH NEXT FROM tbl_cursor INTO #table_cursor
END
CLOSE tbl_cursor
DEALLOCATE tbl_cursor
PRINT #db_cursor + N' Total Tables : ' + CAST( #table_count as varchar(2) )
PRINT N'' -- print another blank line
SET #table_count = 0
FETCH NEXT FROM database_cursor INTO #db_cursor
END
CLOSE database_cursor
DEALLOCATE database_cursor
SET NOCOUNT OFF
The problem is because you're actually always running the INFORMATION_SCHEMA.TABLES query under the master db context.
You'd need to convert the tbl_cursor block into dynamic SQL in order to fully qualify the query with the DB name.
e.g.
SELECT table_name FROM YourDatabase.INFORMATION_SCHEMA.TABLES WHERE....
is essentially what you need to be executing for that cursor.
It's easier to use table variables so you can add rows to #tablist using another dynamic SQL statement
SET NOCOUNT ON
DECLARE #table_count INT
DECLARE #dblist TABLE (DBName VARCHAR(100))
DECLARE #tablist TABLE (TableName VARCHAR(100))
DECLARE #dbname varchar(100), #tabname varchar(100)
INSERT #dblist
SELECT name FROM sys.databases where name<>N'master'
SELECT TOP 1 #dbname = DBName FROM #dblist
WHILE ##ROWCOUNT <> 0
BEGIN
INSERT #tablist (tableName)
EXEC ('SELECT table_name FROM ' + #dbname + '.information_schema.tables WHERE table_type = ''base table'' ')
SELECT TOP 1 #tabname = tableName FROM #tablist
WHILE ##ROWCOUNT <> 0
BEGIN
--do my stuff
DELETE #tablist WHERE tableName = #tabname
SELECT TOP 1 #tabname = tableName FROM #tablist
END
DELETE #dblist WHERE DBName = #dbname
SELECT TOP 1 #dbname = DBName FROM #dblist
END
You might have to create dynamic SQL. because information_schema will fetch objects only from the current active database against which you are running this query.
you can try sys.objects