Update multiple tables from query result - sql-server

Is it possible to update multiple tables from a query result?
I've tried using a cursor. But it's still not working.
Here's the code :
DECLARE #TableName VARCHAR(MAX)
DECLARE db_cursor CURSOR FOR
SELECT TABLE_NAME
FROM information_schema.columns
WHERE column_name = 'Code1';
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE #TableName
SET Code1 = Code + '_' + Type
FETCH NEXT FROM db_cursor INTO #TableName
END
CLOSE db_cursor
DEALLOCATE db_cursor

Hypothesis
I suppose that OP is trying to dynamically build and execute SQL-code for all tables that have column Code1
Solution
Solution (one of many) could be:
Build cursor of created SQL-expressions
In cycle exec created expressions
Example code
DECLARE #sql_code varchar(max)
DECLARE code_cursor CURSOR FOR
SELECT DISTINCT
'UPDATE '+ TABLE_NAME + ' SET Code1= Code + ''_'' + Type;' AS SQL_CODE
FROM
information_schema.columns -- WHERE column_name = 'Code1';
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #sql_code
WHILE ##FETCH_STATUS = 0
BEGIN
exec(#sql_code)
FETCH NEXT FROM db_cursor INTO #TableName
END
CLOSE db_cursor
DEALLOCATE db_cursor
Caution
I did not tested it (of cause - I don't have similar DB) - so be careful.
Update
It's even simpler would be to modify OP code like this:
DECLARE #TableName VARCHAR(MAX)
DECLARE db_cursor CURSOR
FOR SELECT DISTINCT TABLE_NAME -- note DISTINCT here
FROM information_schema.columns WHERE column_name = 'Code1';
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC('UPDATE '+ #TableName + ' SET Code1 = Code + ''_'' + Type') -- note EXEC here
FETCH NEXT FROM db_cursor INTO #TableName
END
CLOSE db_cursor
DEALLOCATE db_cursor

Related

Pass Variable in SELECT FROM Loop

I'm looking to select from multiple tables (MainTbl) but it will be based on the result set (StateTbl) of which tables would be pulled.
MainTables dbo.TABLE_MO, dbo.TABLE_CA, dbo.TABLE_AL, dbo.TABLE_MI
Only looking to pull based on resultset StateTbl MO, CA, WA
Declare #Loop_Count int = 0
DECLARE #State varchar(2)
DECLARE #SQL varchar(max)
DECLARE db_cursor CURSOR FOR SELECT State FROM StateTbl
OPEN db_cursor
FETCH db_cursor INTO #State
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #SQL =
'
dbo.TABLE_'+ #State +'
'
EXEC(#SQL)
SET #Loop_Count = #Loop_Count + 1
FETCH db_cursor INTO #SQL
END
CLOSE db_cursor
DEALLOCATE db_cursor
Instead of a loop you can leverage dynamic and the StateTbl to build your dynamic sql. Something like this.
declare #SQL nvarchar(max) = ''
select 'select * from TABLE_' + [State] + ' UNION ALL '
from StateTbl
select #SQL = left(#SQL, len(#SQL) - 10)
select #SQL
--uncomment the line below when you satisfied the dynamic sql is written the way you want it.
--exec sp_executesql #SQL

How to dynamically declare a cursor in T-SQL?

I'm trying to use a dynamic query to declare a cursor. Basically I have the name of the table-valued function I will use for the cursor as a column of a table so I must declare the cursor using a SQL statement.
The problem is that T-SQL doesn't recognize myCursor as a valid cursor.
DECLARE #ColumnA nvarchar(250)
DECLARE #ColumnB nvarchar(250)
DECLARE #FunctionName nvarchar(250)
DECLARE #RecordId nvarchar(250)
DECLARE #sqlStatement nvarchar(MAX)
SET #sqlStatement = 'DECLARE myCursor CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY FOR SELECT * FROM ' + #FunctionName + '(''' + #RecordId + ''')'
EXEC sp_executesql #sqlStatement
OPEN myCursor
FETCH NEXT FROM myCursor INTO #ColumnA, #ColumnB
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #ColumnA, #ColumnB
FETCH NEXT FROM myCursor INTO #ColumnA, #ColumnB
END
CLOSE myCursor
DEALLOCATE myCursor
Any help or workarounds are welcome.
EDIT: I've solved the problem by declaring the cursor before and using output from sqlstatement to pass values.
DECLARE #myCursor CURSOR
SET #sqlStatement = 'SET #myCursor = CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY FOR SELECT * FROM ' + #FunctionName + '(''' + #RecordId + ''');OPEN #myCursor;'
EXEC sp_executesql #sqlStatement, N'#Placeholder nvarchar(250), #Placeholdervalue nvarchar(250), #myCursor CURSOR OUTPUT', #Placeholder = #Placeholder, #Placeholdervalue = #Placeholdervalue, #myCursor = #myCursor OUTPUT
It is not the best solution but if you really have to do this - an easier way is to use a dynamic SQL to load the data you need into a global temp table first. The dynamic SQL statement is much simpler i.e.:
SET #sqlStatement = 'SELECT * INTO ##MyGlobalTemp FROM ' + #FunctionName + '(''' + #RecordId + ''')'
EXEC sp_executesql #sqlStatement
Then use a regular (non-dynamic) cursor to loop through the ##MyGlobalTemp table (and don't forgot to drop the temp after you are finished).
i.e.:
DECLARE myCursor CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY FOR SELECT column1, column2, etc.. FROM ##MyGlobalTemp...... etc..
Dynamic cursors could get hairy. Just make sure the temp has a global (##) scope.
Hope this helps.

Transact sql : must declare the scalar variable

I'm trying to iterate over some tables and clear all records.
My code is the following :
DECLARE #table varchar(100)
DECLARE db_cursor CURSOR FOR select name from sys.tables where name like '%cfe_%'
OPEN db_cursor  
FETCH NEXT FROM db_cursor INTO #table
WHILE ##FETCH_STATUS = 0  
BEGIN  
print #table
delete from #table
       FETCH NEXT FROM db_cursor INTO #table  
END  
CLOSE db_cursor  
DEALLOCATE db_cursor
But I receive "Must declare the table variable "#table" at the line "delete..."
I can't see the error.
Thank you
You shoud use dynamic query,
DECLARE #table varchar(100)
,#v_str nvarchar(200)
DECLARE db_cursor CURSOR FOR select name from sys.tables where name like '%cfe_%'
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #table
WHILE ##FETCH_STATUS = 0
BEGIN
print #table
set #v_str = 'delete from '+#table
exec(#v_str)
FETCH NEXT FROM db_cursor INTO #table
END
CLOSE db_cursor
DEALLOCATE db_cursor
You need dynamic delete statement... Try this :
DECLARE #cmd VARCHAR(4000)
DECLARE #table varchar(100)
DECLARE db_cursor CURSOR FOR select name from sys.tables where name like '%cfe_%'
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #table
WHILE ##FETCH_STATUS = 0
BEGIN
SET #cmd = 'DELETE FROM '+#table
EXEC (#cmd)
FETCH NEXT FROM db_cursor INTO #table
END
CLOSE db_cursor
DEALLOCATE db_cursor
Even better would be to not use a cursor here. Looping in sql is a last resort. Also, your query is not going to do exactly what you think it will because you are using like and wanting to find an underscore. The underscore in a LIKE predicate requires it to be escaped with square brackets. As posted your query will return any table with cfe in the name not cfe_.
Once you are comfortable that the dynamic sql string is what you want you can uncomment it to execute it.
declare #SQL nvarchar(max) = ''
select #SQL = #SQL + 'delete from ' + name + ';'
from sys.tables
where name like '%cfe[_]%'
select #SQL
--exec sp_executesql #SQL
We can also use while loop for this process
DECLARE #Min Int,#max Int
IF Object_id('Tempdb..#DeleteList')IS NOT NULL
DROP TABLE #DeleteList
CREATE TABLE #DeleteList (Id Int Identity,Name varchar(100))
INSERT INTO #DeleteList(Name)
SELECT name FROM sys.tables WHERE CHARINDEX('cfe_',name)>0
SELECT #Min=Min(Id) FROm #DeleteList
SELECT #max=MAX(Id) FROm #DeleteList
While(#Min<=#max)
Begin
Declare #TableName Varchar(50),
#Sql Nvarchar(max)
SELECT #TableName=Name From #DeleteList Where id=#Min
SET #Sql='DELETE From '+#TableName
Exec (#Sql)
SET #Min=#Min+1
END
But if the deleting tables have foreign key refrences it will throw error so that first you need delete records from child and then go to Parent table
You will need to do something like;
EXEC sp_executesql #statement = N'DELETE FROM ' + #table
because currently you are trying to delete from a String variable, not the table named the same as the variable

Convert Table name from lower case to upper case

The script below shows an example query for data that have been converted from lower case, but it only changed the data on one column in the table.
Use MYF601T
Go
UPDATE ROAD_LINE
SET NAM = UPPER(NAM)
However, the following script that I'm trying to write is to convert all on all columns on all tables, but the result generated with errors.
Use MYF601T
Go
UPDATE INFORMATION_SCHEMA.TABLES
SET INFORMATION_SCHEMA.TABLES.TABLE_SCHEMA = UPPER(INFORMATION_SCHEMA.TABLES.TABLE_SCHEMA
How to do this for all tables and all columns inside?
If for whather reasons you want to convert your tables names to Upper case, you can:
use a cursor that will select the tables you want to rename
loop through the table list
rename it using sp_rename or update it
Note that you have to update the Select in the cursor to suit your needs (select column or table name you want, ...)
This will rename tables:
declare #TABLE_NAME sysname, #TABLE_SCHEMA sysname
declare #TABLE sysname, #newName sysname
declare table_cursor Cursor
For Select TABLE_NAME, TABLE_SCHEMA From INFORMATION_SCHEMA.TABLES Where TABLE_NAME like 'xyz%' -- and TABLE_SCHEMA like ...
open table_cursor
Fetch Next From table_cursor Into #TABLE_NAME, #TABLE_SCHEMA;
While ##FETCH_STATUS = 0
Begin
Set #TABLE = quotename(UPPER(#TABLE_SCHEMA)) + '.' + quotename(UPPER(#TABLE_NAME))
Set #newName = UPPER(#TABLE_NAME)
print 'rename ' + #TABLE + ' to ' + #newName
-- uncomment next like if you really want to rename them
--exec sp_rename #TABLE, #newName
Fetch Next From table_cursor Into #TABLE_NAME, #TABLE_SCHEMA;
End
Close table_cursor
Deallocate table_cursor
If you want to update all columns xyz in table zyx, you can use this:
declare #TABLE_NAME sysname, #TABLE_SCHEMA sysname, #COLUMN_NAME sysname
declare #TABLE sysname, #sql nvarchar(max)
declare table_cursor Cursor
For Select TABLE_NAME, TABLE_SCHEMA, COLUMN_NAME From INFORMATION_SCHEMA.COLUMNS
Where COLUMN_NAME like 'xxx' -- and data_type '' ... and TABLE_NAME like 'xyz%' ... and TABLE_SCHEMA like ...
open table_cursor
Fetch Next From table_cursor Into #TABLE_NAME, #TABLE_SCHEMA, #COLUMN_NAME;
While ##FETCH_STATUS = 0
Begin
Set #TABLE = quotename(#TABLE_SCHEMA) + '.' + quotename(#TABLE_NAME)
set #sql = 'Update ' + #TABLE + ' set ' + #COLUMN_NAME + ' = UPPER(' + #COLUMN_NAME + ')'
print #sql
-- uncomment next like if you really want to execute them
--exec sp_executesql #sql
Fetch Next From table_cursor Into #TABLE_NAME, #TABLE_SCHEMA, #COLUMN_NAME;
End
Close table_cursor
Deallocate table_cursor
Use a dynamic query to update all the column content to upper case.
Query
declare #query varchar(max)
select #query =
stuff
(
(
select ';update ' + table_name + ' ' +
'set ' + column_name + ' = upper(' + column_name + ')'
from information_schema.columns
where table_name = 'ROAD_LINE'
order by table_name,column_name
for xml path('')
)
, 1, 1, '')
execute(#query);

How to query current row's DB name in SQL server?

TableA exists in all 4 DBs, run this,
Use DB1
go
select CurrentDB=DB_NAME(), * From DB1..TableA union all
select CurrentDB=DB_NAME(), * From DB2..TableA union all
select CurrentDB=DB_NAME(), * From DB3..TableA union all
select CurrentDB=DB_NAME(), * From DB4..TableA
always got CurrentDB ='DB1'. is there a Simple way to get DB2,3,4 when the rows are pulling from non-DB1?
Trying to avoid hard code.
Create the same view in each database that returns the value of DB_NAME() as a column. Then, in the union, the each row will include the database name.
Try this
Use Master
set NOCOUNT ON;
Declare #db_name Varchar(12)
Declare #sql Varchar(1000)
Declare db_cursor CURSOR FOR
SELECT [name]
FROM sys.databases Where [name] like 'DB[123456789]'
Open db_cursor
Fetch Next FROM db_cursor INTO #db_name
if ##FETCH_STATUS = 0
begin
Select #sql = 'select ''' + #db_name + ''', * From ' + #db_name + '..TableA'
Fetch Next FROM db_cursor INTO #db_name
While ##FETCH_STATUS = 0
begin
select #sql = #sql + ' Union all select ''' +
#db_name + ''', * From ' + #db_name + '..TableA'
Fetch NEXT FROM db_cursor INTO #db_name
end
exec #sql
end
Close db_cursor
Deallocate db_cursor
Not tested, but basic idea is get all the matching db names. Build the sql statement, then exec it.

Resources