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
Related
I need to create a variable that lists all the existing databases in my system, because I need it and I don't know how to do it. I have tried to create variables like this one:
DECLARE #nombreBD INT;
SET #nombreBD = (SELECT [database_id] FROM sys.databases Where name = 'model' )
SELECT #nombreBD AS Database_ID
PRINT #nombreBD
GO
This variable gets me only the name I put in the "WHERE" parameter but I need to get them all.
The table sys.databases shows you all the existing databases in the system and I need to get a boolean value from it, I thought to get it from the column "database_id" that's why I declared this variable.
This creates a table name #DBList with a column nombreBD
and inserts the database_id to the column,
then it shows all your sql-server database database_id
BEGIN
DECLARE #DBList TABLE (nombreBD INT)
INSERT INTO #DBList(nombreBD) SELECT database_id FROM sys.databases
SELECT * FROM #DBList
END
Is that what you need ?
To achieve what you want, you will need to use some dynamic SQL. Something like this ought to work for your case:
DECLARE #DBList TABLE (nombre varchar(50));
INSERT INTO #DBList(nombre) SELECT name FROM sys.databases
WHERE name NOT IN ('master','tempdb','msdb');
declare #name nvarchar(50);
declare #sql nvarchar(2000);
DECLARE db_Cursor CURSOR FOR
SELECT nombre FROM #DBList;
OPEN db_Cursor;
FETCH NEXT FROM db_Cursor INTO #name;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = N'USE ' + #name + N';'
exec sp_executesql #sql;
SET #sql = N'SELECT DB_NAME() AS DatabaseName, ''guest'' AS Database_User, [permission_name], [state_desc]
FROM sys.database_permissions WHERE [grantee_principal_id] = DATABASE_PRINCIPAL_ID(''guest'') AND [state_desc] LIKE ''GRANT%'' AND [permission_name] = ''CONNECT'';';
exec sp_executesql #sql;
FETCH NEXT FROM db_Cursor INTO #name;
END;
CLOSE db_Cursor;
DEALLOCATE db_Cursor;
Notice that I have changed the table variable to hold the database names, not their ids. This is because the USE statement takes the name not the id.
The cursor loops through the values, builds the various sql statements and executes them.
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'm building a fun stored procedure that will use dynamic SQL, sp_executesql with parameters, to allow some alter statements for a column in all database tables if the column name exists ( As you can see I used a cursor for loop all the tables on DB)
I built a test but the parameter doesn't work, I get the next error on each alter table statement that runs
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '#parTablename'.
The next is the code
SET NOCOUNT ON;
GO
DECLARE #tablename varchar(100);
DECLARE #alteredColumn varchar(100)='[mycolumn] [datetimeoffset](0) NOT NULL;';
DECLARE #column varchar(100)='mycolumn';
DECLARE #parDefinition nvarchar(500) = N'#parTablename nvarchar(100)';
DECLARE #sqlCommand nvarchar(1000)= N'ALTER TABLE #parTablename ALTER COLUMN '+#alteredColumn;
DECLARE ALTERCURSOR CURSOR LOCAL FAST_FORWARD FOR
SELECT name AS tablename
FROM sys.Tables
OPEN ALTERCURSOR;
FETCH NEXT FROM ALTERCURSOR INTO #tablename
WHILE ##FETCH_STATUS = 0
BEGIN
--print #tablename
IF EXISTS(SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tablename AND COLUMN_NAME = #column)
BEGIN
EXECUTE sp_executesql #sqlCommand, #parDefinition,#parTablename = #tablename
END
FETCH NEXT FROM ALTERCURSOR INTO #tablename
END
CLOSE ALTERCURSOR;
DEALLOCATE ALTERCURSOR;
SET NOCOUNT OFF;
GO
SOLUTION
Apparently is not possible to send a table name as a parameter, instead of that I used the #SeanLange option for degub with a little modification
SET #sqlCommand =Replace(#sqlCommand, '#parTablename',QUOTENAME(#tablename))
EXECUTE sp_executesql #sqlCommand
You can't stick a parameter in the middle of your dynamic sql like this. You need to use PRINT instead of EXECUTE to debug this. I wouldn't use a cursor for this myself but if you go that path you will have to do something like this before the EXECUTE statement.
Set #sqlCommand = Replace(sqlCommand, '#parTablename', #parTablename)
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'm trying to switch the current database with a SQL statement.
I have tried the following, but all attempts failed:
USE #DatabaseName
EXEC sp_sqlexec #Sql -- where #Sql = 'USE [' + #DatabaseName + ']'
To add a little more detail.
EDIT: I would like to perform several things on two separate database, where both are configured with a variable. Something like this:
USE Database1
SELECT * FROM Table1
USE Database2
SELECT * FROM Table2
The problem with the former is that what you're doing is USE 'myDB' rather than USE myDB.
you're passing a string; but USE is looking for an explicit reference.
The latter example works for me.
declare #sql varchar(20)
select #sql = 'USE myDb'
EXEC sp_sqlexec #Sql
-- also works
select #sql = 'USE [myDb]'
EXEC sp_sqlexec #Sql
exec sp_execsql #Sql
The DB change only lasts for the time to complete #sql
http://blog.sqlauthority.com/2007/07/02/sql-server-2005-comparison-sp_executesql-vs-executeexec/
I have the same problem, I overcame it with an ugly -- but useful -- set of GOTOs.
The reason I call the "script runner" before everything is that I want to hide the complexity and ugly approach from any developer that just wants to work with the actual script. At the same time, I can make sure that the script is run in the two (extensible to three and more) databases in the exact same way.
GOTO ScriptRunner
ScriptExecutes:
--------------------ACTUAL SCRIPT--------------------
-------- Will be executed in DB1 and in DB2 ---------
--TODO: Your script right here
------------------ACTUAL SCRIPT ENDS-----------------
GOTO ScriptReturns
ScriptRunner:
USE DB1
GOTO ScriptExecutes
ScriptReturns:
IF (db_name() = 'DB1')
BEGIN
USE DB2
GOTO ScriptExecutes
END
With this approach you get to keep your variables and SQL Server does not freak out if you happen to go over a DECLARE statement twice.
Just wanted to thank KM for his valuable solution.
I implemented it myself to reduce the amount of lines in a shrinkdatabase request on SQLServer.
Here is my SQL request if it can help anyone :
-- Declare the variable to be used
DECLARE #Query varchar (1000)
DECLARE #MyDBN varchar(11);
-- Initializing the #MyDBN variable (possible values : db1, db2, db3, ...)
SET #MyDBN = 'db1';
-- Creating the request to execute
SET #Query='use '+ #MyDBN +'; ALTER DATABASE '+ #MyDBN +' SET RECOVERY SIMPLE WITH NO_WAIT; DBCC SHRINKDATABASE ('+ #MyDBN +', 1, TRUNCATEONLY); ALTER DATABASE '+ #MyDBN +' SET RECOVERY FULL WITH NO_WAIT'
--
EXEC (#Query)
try this:
DECLARE #Query varchar(1000)
DECLARE #DatabaseName varchar(500)
SET #DatabaseName='xyz'
SET #Query='SELECT * FROM Server.'+#DatabaseName+'.Owner.Table1'
EXEC (#Query)
SET #DatabaseName='abc'
SET #Query='SELECT * FROM Server.'+#DatabaseName+'.Owner.Table2'
EXEC (#Query)
I case that someone need a solution for this, this is one:
if you use a dynamic USE statement all your query need to be dynamic, because it need to be everything in the same context.
You can try with SYNONYM, is basically an ALIAS to a specific Table, this SYNONYM is inserted into the sys.synonyms table so you have access to it from any context
Look this static statement:
CREATE SYNONYM MASTER_SCHEMACOLUMNS FOR Master.INFORMATION_SCHEMA.COLUMNS
SELECT * FROM MASTER_SCHEMACOLUMNS
Now dynamic:
DECLARE #SQL VARCHAR(200)
DECLARE #CATALOG VARCHAR(200) = 'Master'
IF EXISTS(SELECT * FROM sys.synonyms s WHERE s.name = 'CURRENT_SCHEMACOLUMNS')
BEGIN
DROP SYNONYM CURRENT_SCHEMACOLUMNS
END
SELECT #SQL = 'CREATE SYNONYM CURRENT_SCHEMACOLUMNS FOR '+ #CATALOG +'.INFORMATION_SCHEMA.COLUMNS';
EXEC sp_sqlexec #SQL
--Your not dynamic Code
SELECT * FROM CURRENT_SCHEMACOLUMNS
Now just change the value of #CATALOG and you will be able to list the same table but from different catalog.
If SQLCMD is an option, it supports scripting variables above and beyond what straight T-SQL can do. For example: http://msdn.microsoft.com/en-us/library/ms188714.aspx
You can do this:
Declare #dbName nvarchar(max);
SET #dbName = 'TESTDB';
Declare #SQL nvarchar(max);
select #SQL = 'USE ' + #dbName +'; {can put command(s) here}';
EXEC (#SQL);
{but not here!}
This means you can do a recursive select like the following:
Declare #dbName nvarchar(max);
SET #dbName = 'TESTDB';
Declare #SQL nvarchar(max);
SELECT #SQL = 'USE ' + #dbName + '; ' +(Select ... {query here}
For XML Path(''),Type)
.value('text()[1]','nvarchar(max)');
Exec (#SQL)
Use exec sp_execsql #Sql
Example
DECLARE #sql as nvarchar(100)
DECLARE #paraDOB datetime
SET #paraDOB = '1/1/1981'
SET #sql=N'SELECT * FROM EmpMast WHERE DOB >= #paraDOB'
exec sp_executesql #sql,N'#paraDOB datetime',#paraDOB
-- If you are using a variable for the database name.
-- Try something like this.
DECLARE #DBName varchar(50)
Set #DBName = 'Database1'; /* could be passed in by a parameter. */
IF( #DBName = 'Database1')
Begin
USE [Database1];
SELECT FROM Table1;
End
IF( #DBName = 'Database2')
Begin
USE [Database2];
SELECT FROM Table2;
End
IF( #DBName is null)
Begin
USE [Database1];
End