we have some database with a lot of views, functions and procedures.
We will update some of them. Therefore i´ve written this script.
My question is, is that a common way and is that the right way?
Any suggestion will be appreciated.
-- update procedures and functions
USE mydb
GO
DECLARE #ticker nvarchar(255)
DECLARE #definition nvarchar(max)
DECLARE #newdefinition nvarchar(max)
DECLARE crsVorgang SCROLL CURSOR FOR
SELECT ROUTINE_NAME,ROUTINE_DEFINITION FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_CATALOG = 'mydb' and ROUTINE_DEFINITION like '%something%'
ORDER BY ROUTINE_NAME
OPEN crsVorgang
FETCH FIRST FROM crsVorgang INTO #ticker, #definition
WHILE (##FETCH_STATUS <> -1)
BEGIN
set #newdefinition = REPLACE(#definition,'sometext', 'newtext')
--print #newdefinition
update INFORMATION_SCHEMA.ROUTINES
set ROUTINE_DEFINITION = #newdefinition
where ROUTINE_NAME = #ticker
FETCH NEXT FROM crsVorgang INTO #ticker, #definition
END
CLOSE crsVorgang
DEALLOCATE crsVorgang
GO
The answer is, it is not possible with update INFORMATION_SCHEMA.ROUTINES, cause it is not allowed.
The right way (for me) to a reproduceable bulk update from lots of procedures and functions is now a drop and create, so i have modified my script to the following:
USE [mydb]
GO
DECLARE #ticker nvarchar(255)
DECLARE #definition nvarchar(max)
DECLARE #routinetype nvarchar(255)
DECLARE #newdefinition nvarchar(max)
DECLARE #dropdefinition nvarchar(max)
DECLARE crsVorgang SCROLL CURSOR FOR
SELECT ROUTINE_NAME,ROUTINE_DEFINITION, ROUTINE_TYPE FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_CATALOG = 'mydb' and ROUTINE_DEFINITION like '%something%'
ORDER BY ROUTINE_NAME
OPEN crsVorgang
FETCH FIRST FROM crsVorgang INTO #ticker, #definition, #routinetype
WHILE (##FETCH_STATUS <> -1)
BEGIN
set #dropdefinition = 'DROP '+ #routinetype +' [dbo].'+#ticker
set #newdefinition = REPLACE(#definition,'sometext', 'newtext')
exec (#dropdefinition)
exec (#newdefinition)
FETCH NEXT FROM crsVorgang INTO #ticker, #definition, #routinetype
END
CLOSE crsVorgang
DEALLOCATE crsVorgang
GO
thanks for your spent time
Related
I'm currently learning SQL and trying to think of exercises for myself and I can't seem to make this one work even though it seems simple:
I'm trying to run a cursor through all the filtered tables within my db so that then I could pass that table name to a variable which will be used within a DynamicSQL inside the cursor. The end result should be all values from every column that has the column 'empid' in them.
However, the message returns as "Commands completed successfully" but I get to see no results despite my select statement.
I'm trying to run something like this:
declare #tablename nvarchar(200);
declare #empid int;
declare #sql nvarchar(200) = N'select * from ' + #tablename + N' where empid = ' +#empid;
declare tablecursor cursor for select table_name from information_schema.tables where col_length(table_name, 'empid') is not null;
open tablecursor;
fetch next from tablecursor into #tablename;
while ##fetch_status = 0
begin
execute sp_executesql #sql, 825
fetch next from tablecursor into #tablename;
end
close tablecursor;
deallocate tablecursor;
I've been searching everywhere for answers to make this work but can't find anything. I've tried putting into a stored procedure and then executing it from there but that didn't work either.
Help would be highly appreciated.
DECLARE #SQL Should be outside but assigning the Variable inside the while loop
SET #SQL = N'SELECT * FROM ' + #tableName
Should be in while loop.
The other thing is to increase the length of #SQL Variable.
Thank you kindly for the help. After I listened to your advice I've encountered more errors but at least for these I was able to find answers online. What I also learnt is that you can't have your sql string in quotes when you execute it as that will make SSMS treat #SQL as an actual string and not a variable. I've managed to get it working and my code now looks something like this:
create proc cdr #empid nvarchar(5) as
declare #tablename nvarchar(200);
declare tablecursor cursor for select table_name from information_schema.tables where col_length(table_name, 'empid') is not null;
open tablecursor;
fetch next from tablecursor into #tablename;
declare #sql nvarchar(max)
while ##fetch_status = 0
begin
set #sql = N'select * from ' + #tablename + N' where empid = ' + #empid;
execute sp_executesql #sql
fetch next from tablecursor into #tablename;
end
close tablecursor;
deallocate tablecursor;
I know you can do this easily using the GUI in SSMS. But,is there a way to include all the articles with TSQL instead of doing them one by one using sp_addarticle?
My initial idea is returning all the tables names(using a sys query) and then using a loop to feed them to sp_addarticle. I'm wondering if there's a smarter way for example a built-in variable that I can assign 'all' to it?
This is how I did it
USE [DatabaseName]
DECLARE #name sysname
DECLARE #getid CURSOR
SET #getid = CURSOR FOR
-- Select all tables name
SELECT [name]
FROM [DataBaseName].[sys].[tables]
WHERE is_ms_shipped=0
-- While loop
OPEN #getid
FETCH NEXT
FROM #getid INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
-- add article
exec sp_addarticle #publication = #publication
,#article = #name
,#source_object = #name
,#del_cmd = 'NONE'
FETCH NEXT
FROM #getid INTO #name
END
CLOSE #getid
DEALLOCATE #getid
I have over 100 tables in SQL Server 2000 with the same column name in each table. Now I want to update a value in 100 tables at once using a SQL update statement.
How do I do that? I try to google and stackoverflow but not really help.
Thanks so much
Create a cursor for all table in your database and using dynamic query to execute.
This script will be help you do this.
--USE [Your DB]
--GO
DECLARE #tableName VARCHAR(100)
DECLARE #sqlQuery VARCHAR(MAX)
DECLARE curTable CURSOR FOR SELECT name FROM sys.objects WHERE type_desc = 'USER_TABLE' AND name NOT IN ('sysdiagrams')
OPEN curTable
FETCH NEXT FROM curTable INTO #tableName
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #sqlQuery = 'UPDATE ' + #tableName + 'SET [YourCol1] = [YourVal1], [YourCol2] = [YourVal2] ...'
PRINT #sqlQuery
EXECUTE sp_executesql #sqlQuery
FETCH NEXT FROM curTable INTO #tableName
END
CLOSE curTable
DEALLOCATE curTable
I would like to write a script which produces various statements out of a database.
Something like :
select 'DROP TABLE ['+ name + ']' from sys.objects where type = 'T' ;
I would like to automatically collect all output of such statements in a new file, and then I would like to execute this file. Is this possible ?
Important: The output should of course be without headers and without any other error/success, messages and so on.
In the optimal case, all necessary options for this should be set in the script itself, other than setting them in the user interface.
First, you create you dynamic script, something like...
DECLARE #sql NVARCHAR(MAX)
SELECT #sql =
COALESCE(#sql + CHAR(13), '') +
'DROP TABLE ['+ name + ']'
FROM sys.objects
WHERE [type] = 'T'
Execute that...
EXEC(#sql)
Then print that out to Messages-window...
PRINT #sql
And finally go to Messages-window, right-click it, select "Save results as...", Save as type > all files, and write your file name like myfile.sql
EDIT
I would never, EVER execute something like this automatically and without transaction. I'd rather save a script from Messages-window, open it, review it and then execute.
Are you wanting something like this?
If you only want to print the script use osql and a script something like this
DECLARE #schema VARCHAR(255)
DECLARE #table VARCHAR(255)
DECLARE PrintOutputCursor CURSOR LOCAL FAST_FORWARD FOR
SELECT [TABLE_SCHEMA], [TABLE_NAME]
FROM INFORMATION_SCHEMA.TABLES
OPEN PrintOutputCursor
FETCH NEXT FROM PrintOutputCursor INTO #schema, #table
WHILE ##FETCH_STATUS = 0 BEGIN
PRINT 'DROP TABLE ['+ #schema + '].[' + #table + '];'
FETCH NEXT FROM PrintOutputCursor INTO #schema, #table
END
CLOSE PrintOutputCursor
DEALLOCATE PrintOutputCursor
If you want to execute the script using osql use this script (NOT RECOMMENDED)
DECLARE #schema VARCHAR(255)
DECLARE #table VARCHAR(255)
DECLARE #exec VARCHAR(4000)
DECLARE PrintOutputCursor CURSOR LOCAL FAST_FORWARD FOR
SELECT [TABLE_SCHEMA], [TABLE_NAME]
FROM INFORMATION_SCHEMA.TABLES
OPEN PrintOutputCursor
FETCH NEXT FROM PrintOutputCursor INTO #schema, #table
WHILE ##FETCH_STATUS = 0 BEGIN
SET #exec = 'DROP TABLE ['+ #schema + '].[' + #table + '];'
-- Uncomment the following to execute the dynamic statement
-- EXEC (#exec)
FETCH NEXT FROM PrintOutputCursor INTO #schema, #table
END
CLOSE PrintOutputCursor
DEALLOCATE PrintOutputCursor
I have a strange problem with my nested cursors and I have no idea what it's all about.
Here's my T-SQL code:
declare #dbname varchar(50)
declare #servername varchar(50)
declare srv cursor for select servername from test.dbo.servers
declare #str varchar(200)
truncate table test.dbo.temp
open srv
fetch next from srv into #servername
while ##fetch_status = 0
begin
set #str = 'Data Source='+#servername+';Integrated Security=SSPI'
declare db cursor for select name from opendatasource('SQLNCLI', #str).master.dbo.sysdatabases
open db
fetch next from db into #dbname
while ##fetch_status = 0
begin
insert test.dbo.temp (dbname, servername) values (#dbname, #servername)
fetch next from db into #dbname
end
fetch next from srv into #servername
close db
deallocate db
end
close srv
deallocate srv
It gives me next error message:
Incorrect syntax near '#str'.
[SQLSTATE 42000] (Error 102)
Looks like the problem is in giving the variable as a parameter to opendatasource function. But why? And how to avoid this problem?
You are correct that variables cannot be passed to OPENDATASOURCE. Instead You must use a literal instead. As much as we discourage using dynamic SQL, there are some cases that it is unavoidable. Try something like this:
declare #dbname varchar(50)
declare #servername varchar(50)
declare srv cursor for select servername from test.dbo.servers
declare #str varchar(200)
declare #sql nvarchar(MAX)
truncate table test.dbo.temp
open srv
fetch next from srv into #servername
while ##fetch_status = 0
begin
SET #sql = N'
declare db cursor for select name from opendatasource(''SQLNCLI'', ''Data Source='+#servername+';Integrated Security=SSPI'').master.dbo.sysdatabases
open db
fetch next from db into #dbname
while ##fetch_status = 0
begin
insert test.dbo.temp (dbname, servername) values (#dbname, #servername)
fetch next from db into #dbname
end
close db
deallocate db
'
EXEC sp_executesql
#sql,
N'#dbname varchar(50),
#servername varchar(50)',
#dbname,
#servername
fetch next from srv into #servername
end
close srv
deallocate srv
If you need to use nested cursors, you are doing something wrong. There are very few reasons to use a cursor instead of some other set-based operation, and using a cursor within a cursor is like the ultimate SQL Server anti-pattern.
For your inner cursor, you could change it to use the undocumented sp_msforeachdb function (which apparently creates a cursor behind the scenes):
open srv
fetch next from srv into #servername
while ##fetch_status = 0
begin
EXEC sp_msforeachdb '
Data Source='+#servername+';Integrated Security=SSPI
insert test.dbo.temp (dbname, servername) values (?, #Servername)'
fetch next from srv into #servername
end
close srv
deallocate srv
You may need to enclose the ? in single quotes and escape them, like:
EXEC sp_msforeachdb 'insert test.dbo.temp (dbname, servername) values (''?'', #Servername)