Multiple values in a cursor which executes a stored procedure - sql

I have a cursor which executes a stored procedure. I have introduced a new variable dbname into the cursor and I get an exception error near dbname. This change was introduced so that the stored procedure storedProc_getOutputsByRuncan be executed on different databases.
#
exec( '
DECLARE #dbName nvarchar(100)
DECLARE #runID INT
DECLARE #getRunDetails CURSOR
DECLARE #delayLoad bigint
SET #delayLoad = 1
SET #getRunDetails = CURSOR FOR
SELECT DBName, RunID from ' + #temp_table_runID + '
OPEN #getRunDetails
FETCH NEXT
FROM #getRunDetails INTO #dbName, #runID
WHILE ##FETCH_STATUS = 0
BEGIN
-- I have tried at this point printing #runid and #dbname and it prints fine.Error in line below
INSERT INTO ' + #temp_table_outputs + ' Execute ''#dbname''.dbo.storedProc_getOutputsByRun
#runID, #delayLoad
FETCH NEXT
FROM #getRunDetails INTO #dbName, #runID
END
CLOSE #getRunDetails
DEALLOCATE #getRunDetails')

If you were to wrap all this up in its own variable, and print it, this line
'INSERT INTO ' + #temp_table_outputs + ' Execute ''#dbname''.dbo.storedProc_getOutputsByRun'
Would yield something like this:
INSERT INTO myTable Execute '#dbname'.dbo.storedProc_getOutputsByRun
The problem being you're not escaping the string correctly to replace #dbname with an actual value.
The fix would be to nest another string within the main string, and execute that.
Something like this INSIDE the main string:
declare #sql nvarchar(max)
set #sql = ''INSERT INTO ' + #temp_table_outputs + ' Execute ''+#dbname+''.dbo.storedProc_getOutputsByRun ''+cast(#runID as varchar)+'', ''+cast(#delayLoad as varchar)+''''
print #sql
exec(#sql)
Which would yield a final product similar to this...
exec( '
DECLARE #dbName nvarchar(100)
DECLARE #runID INT
DECLARE #getRunDetails CURSOR
DECLARE #delayLoad bigint
SET #delayLoad = 1
SET #getRunDetails = CURSOR FOR
SELECT DBName, RunID from ' + #temp_table_runID + '
OPEN #getRunDetails
FETCH NEXT
FROM #getRunDetails INTO #dbName, #runID
WHILE ##FETCH_STATUS = 0
BEGIN
declare #sql nvarchar(max)
set #sql = ''INSERT INTO ' + #temp_table_outputs + ' Execute ''+#dbname+''.dbo.storedProc_getOutputsByRun ''+cast(#runID as varchar)+'', ''+cast(#delayLoad as varchar)+''''
print #sql
--exec(#sql)
FETCH NEXT
FROM #getRunDetails INTO #dbName, #runID
END
CLOSE #getRunDetails
DEALLOCATE #getRunDetails')
You may need to tweak this a bit, but this is easy now, just comment out the EXEC(#SQL) as I have done inside the new code, and print it out to screen. Copy the messages to a new SSMS window, and check the syntax.

Related

Update specific column in all tables base on specific value

I'm trying to update all table based on my value. This is a script Task in my SSIS package.
But I get the error:
Multiple-step OLE DB operation generated errors. Check each OLE DB status value, if available. No work was done.
Code looks like this:
DECLARE #Column_name varchar(MAX)
DECLARE #Column_Datatype varchar(max)
SET #COLUMN_NAME='site_id'
SET #COLUMN_DATATYPE='varchar(10)'
------------------------------------------------Code---------------------------------------------------
GO
--Declare Variables
DECLARE #TableName VARCHAR(100)
DECLARE #TableSchema VARCHAR(100)
DECLARE #COLUMN_NAME VARCHAR(50)
DECLARE #COLUMN_NAME_UPDATE VARCHAR(50)
SET #COLUMN_NAME_UPDATE = ?
SET #COLUMN_NAME='site_id'
DECLARE #COLUMN_DATATYPE VARCHAR(50)
SET #COLUMN_DATATYPE='varchar(max)'
--Declare Cursor
DECLARE CUR CURSOR FOR
SELECT TABLE_SCHEMA,
TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
--OPEN CURSOR
OPEN CUR
--Fetch First Row
FETCH NEXT FROM CUR INTO #TableSchema,#TableName
--Loop
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #SQL NVARCHAR(MAX)
SET #SQL= ( SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME=#TableName AND COLUMN_NAME=#COLUMN_NAME
and Table_Schema=#TableSchema)
BEGIN
SET #SQL='UPDATE '+ #TableSchema+'.'+ '[' + #TableName + ']' + ' SET '+#COLUMN_NAME + '='
+ '''' + #COLUMN_NAME_UPDATE + '''' + 'WHERE site_id IS NULL '
PRINT #SQL
EXEC ( #SQL)
END
FETCH NEXT FROM CUR INTO #TableSchema,#TableName
END
--Close and Deallocate Cursor
CLOSE CUR
DEALLOCATE CUR
I use a variable like input.
What's wrong?

Only fetching first value in column

CREATE PROC [dbo].[usp_InsertGenerator]
AS
BEGIN
DECLARE #tablename varchar(max)
DECLARE cursCol1 CURSOR FOR
SELECT name FROM sys.tables
OPEN cursCol1
FETCH NEXT FROM cursCol1 INTO #tablename
DECLARE cursCol CURSOR FOR
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = #tableName
OPEN cursCol
DECLARE #string nvarchar(3000)
DECLARE #stringData nvarchar(3000)
DECLARE #dataType nvarchar(1000)
SET #string='INSERT '+#tableName+'('
SET #stringData=''
DECLARE #colName nvarchar(50)
FETCH NEXT FROM cursCol INTO #colName,#dataType
IF ##fetch_status<>0
BEGIN
PRINT 'Table '+#tableName+' not found, processing skipped.'
--FETCH NEXT FROM cursCol1 INTO #tablename
CLOSE curscol
DEALLOCATE curscol
RETURN
END
WHILE ##FETCH_STATUS=0
--FETCH NEXT FROM cursCol1 INTO #tablename
BEGIN
IF #dataType in ('varchar','char','nchar','nvarchar')
BEGIN
SET #stringData=#stringData+'''''''''+
isnull('+#colName+','''')+'''''',''+'
END
ELSE
BEGIN
SET #stringData=#stringData+'''''''''+
isnull(cast('+#colName+' as varchar(200)),''0'')+'''''',''+'
END
SET #string=#string+#colName+','
FETCH NEXT FROM cursCol INTO #colName ,#dataType
END
BEGIN
DECLARE #Query nvarchar(4000)
SET #query ='SELECT '''+substring(#string,0,len(#string)) + ')
VALUES(''+ ' + substring(#stringData,0,len(#stringData)-2)+'''+'')''
FROM '+#tableName
PRINT (#query)
CLOSE cursCol1
DEALLOCATE cursCol1
CLOSE cursCol
DEALLOCATE cursCol
END
END
GO
When executing the procedure I am only getting first value(Row) from name column in sys.tables.
I want it for all the rows in the sys.tables.
Query should take each table name one by one then execute the query for every table so that I can get insert statement for all the tables.
Thanks in advance .
Please try using cursor to get name, cursCol1 Should be closed at last after cursCol. FETCH NEXT is also missing for cursCol1
CREATE PROC [dbo].[usp_InsertGenerator]
AS
BEGIN
DECLARE #tablename varchar(max)
DECLARE #tbl table (insertVal varchar(max))
DECLARE cursCol1 CURSOR FOR
SELECT name FROM sys.tables
OPEN cursCol1
FETCH NEXT FROM cursCol1 INTO #tablename
WHILE ##FETCH_STATUS=0
begin
DECLARE cursCol CURSOR FOR
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = #tableName
OPEN cursCol
DECLARE #string nvarchar(3000)
DECLARE #stringData nvarchar(3000)
DECLARE #dataType nvarchar(1000)
SET #string='INSERT '+#tableName+'('
SET #stringData=''
DECLARE #colName nvarchar(50)
FETCH NEXT FROM cursCol INTO #colName,#dataType
IF ##fetch_status<>0
BEGIN
PRINT 'Table '+#tableName+' not found, processing skipped.'
FETCH NEXT FROM cursCol1 INTO #tablename
CLOSE curscol
DEALLOCATE curscol
RETURN
END
WHILE ##FETCH_STATUS=0
--FETCH NEXT FROM cursCol1 INTO #tablename
BEGIN
IF #dataType in ('varchar','char','nchar','nvarchar')
BEGIN
SET #stringData=#stringData+'''''''''+
isnull('+#colName+','''')+'''''',''+'
END
ELSE
BEGIN
SET #stringData=#stringData+'''''''''+
isnull(cast('+#colName+' as varchar(200)),''0'')+'''''',''+'
END
SET #string=#string+#colName+','
FETCH NEXT FROM cursCol INTO #colName ,#dataType
END
BEGIN
DECLARE #Query nvarchar(4000)
SET #query ='SELECT '''+substring(#string,0,len(#string)) + ')
VALUES(''+ ' + substring(#stringData,0,len(#stringData)-2)+'''+'')''
FROM '+#tableName
INSERT INTO #tbl (insertVal) EXEC (#query)
-- PRINT (#query)
END
CLOSE cursCol
DEALLOCATE cursCol
FETCH NEXT FROM cursCol1 INTO #tablename
END
CLOSE cursCol1
DEALLOCATE cursCol1
SELECT * FROM #tbl
END

Loop through Query and Update field

I'm trying to loop through a fields defined in a query to an update statement.
I have the following SQL:
Declare #SQL varchar(max)
#SQL= 'Select [a],[b],[c],[d],[e]....[z]
From Table1;'
I want to be able to loop through all the fields [a]-[z] and update via the following statement:
Update Table 1
Set [a] = Case when [a] = 'Not at all' Then 0
when [a] = 'Very Much' Then 10 End
Field names are not actually [a]..[z]; I can't run the the update statement on the whole table, only a specific set of field names.
Struggling to write it programatically in SQL Server.
Declare #SQL varchar(max)
Declare #name varchar(100)
DECLARE #getid CURSOR
Set #getid = cursor for
SELECT name
FROM
sys.dm_exec_describe_first_result_set('Select [a],[b],[c],[d],[e]....[z]
From Table1', NULL, 0)
Open #getid
FETCH NEXT
FROM #getid INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQL = 'Update Table1
Set ' + #name + ' = Case when ' + #name +'= ''Very Much'' Then ''10''
when ' + #name + ' = ''Not at all'' Then ''0''
Else ' + #name + ' End'
Exec(#SQL)
FETCH NEXT
FROM #getid INTO #name
END
CLOSE #getid
DEALLOCATE #getid
Basically dm_exec_describe_first_result_set is grabbing the fieldnames and outputting it as a recordset. Then we are just passing the the each of the records to #name and use it form our update statement and then executing it for each record passed.
Hope this helps someone else! Curious to see if there is a better way.
I think if you want to make it a little more generic I would do something like the following code. This will allow you to not have to write the specific query for every table you want to do this to and you could potentially filter out columns you do not want in the future.
To be clear, I borrowed the SQL to do the actual UPDATE from #Dale-K post and just made it pretty.
DECLARE #strSQL NVARCHAR(1000)
DECLARE #strTable NVARCHAR(100)
DECLARE #strColName VARCHAR(100)
SET #strTable = N'Table1'
CREATE TABLE #COLUMNS(ColName varchar(100))
SET #strSQL = ' select COLUMN_NAME
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = #TableName and DATA_TYPE in (''nvarchar'', ''varchar'')'
INSERT INTO #COLUMNS
EXEC sp_executeSQL #strSQL, N'#TableName nvarchar(100)', #TableName = #strTable
DECLARE csrColumns CURSOR LOCAL FORWARD_ONLY FOR
SELECT ColName FROM #COLUMNS
OPEN csrColumns
FETCH csrColumns INTO #strColName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #strSQL = N'UPDATE ' + #strTable + '
SET ' + #strColName + ' = CASE WHEN ' + #strColName +'= ''Very Much'' THEN ''10''
WHEN ' + #strColName + ' = ''Not at all'' THEN ''0''
ELSE ' + #strColName + ' END'
exec sp_ExecuteSQL #strSQL
FETCH csrColumns INTO #strColName
END
CLOSE csrColumns
DEALLOCATE csrColumns

SQL Cursor within Stored Procedure to populate string variable

I have a stored procedure that contains a cursor to loop through SQL records and populates the string which I will use later as my email text. I'm trying to print it out to verify before I can proceed with it but it seems to not populate the string. Here is my stored procedure in SQL Server 2005.
CREATE PROCEDURE [dbo].[spBody]
AS
DECLARE #MyCursor CURSOR
DECLARE #emailBody nvarchar(max)
DECLARE #statusName nvarchar(max)
DECLARE #deptCode nvarchar(max)
DECLARE #instructors nvarchar(max)
DECLARE #meetingTime nvarchar(max)
SET #MyCursor = CURSOR FAST_FORWARD For
Select StatusName, DeptCode, Instructors, Description from MyTable where StatusID = (select CAST(value AS INT) from Table2 where ConfigOption = 'RequiredStatus')
Open #MyCursor
FETCH NEXT FROM #MyCursor INTO #statusName, #deptCode, #instructors, #meetingTime
WHILE ##FETCH_STATUS = 0
BEGIN
SET #emailBody = #emailBody + #statusName + ' ' + #deptCode + ' ' + #instructors + ' ' + #meetingTime
FETCH NEXT FROM #MyCursor INTO #statusName, #deptCode, #instructors, #meetingTime
END
CLOSE #MyCursor
Print #emailBody
DEALLOCATE #MyCursor
It's because #emailBody starts out as NULL, and any concatenation with NULL yields NULL by default. Do a
SET #emailBody = '';
at the beginning of your script.
Also, strongly consider adding a SET NOCOUNT ON; statement at the top of your stored procedure -- not having NOCOUNT ON can greatly slow the execution of your proc.
Why do you need a cursor for this string concat. Wont the following query suffix
DECLARE #emailBody nvarchar(max)
Set #emailBody = ''
Select #emailBody = #emailBody + StatusName + ' ' + DeptCode + ' ' + Instructors + ' ' + [Description] from MyTable where StatusID = (select CAST(value AS INT) from Table2 where ConfigOption = 'RequiredStatus')
Print #emailBody

Creating SQL UPDATE statements on the fly

I am in the midst of updating data in multiple tables. Currently I have a table that has one field, "sources", that is just a list of all tables that include the field "itemid". I also have a table that has 2 fields, "itemid" and "olditemid". In TSQL, I would like to iterate through the sources and create the update statements on the fly. Here is what I was trying to do but I get some errors in the update statement that my variable is not declared. I am not sure this is even close the correct way I should be doing this. Ideas?
DECLARE #tblName varchar(50)
DECLARE process_cursor CURSOR FOR
SELECT source
FROM tmpTableNames
OPEN process_cursor
FETCH NEXT FROM processcursor
INTO #tblName
WHILE ##FETCH_STATUS = 0
UPDATE #tblName
SET itemid = r.itemid
FROM #tblName v, itemref r
WHERE r.olditemid = v.itemid
FETCH NEXT FROM process_cursor
INTO #tblName
END
CLOSE processcursor
DEALLOCATE processcursor
What you are trying to do is referred to as "dynamic SQL". While you're on the right track, you can't simply stick a variable in place of an object name and execute the query. I'll leave the pitfalls of dynamic SQL to someone else. What you're looking for is this:
DECLARE #tblName varchar(50)
DECLARE process_cursor CURSOR FOR
SELECT source
FROM tmpTableNames
OPEN process_cursor
FETCH NEXT FROM processcursor
INTO #tblName
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #sql NVARCHAR(500)
SELECT #sql = 'UPDATE [' + #tbleName + '] SET itemid = r.itemid FROM [' + #tbleName + '] v, itemref r WHERE r.ilditemid = v.itemid'
EXEC sp_executesql #sql
FETCH NEXT FROM process_cursor
INTO #tblName
END
CLOSE processcursor
DEALLOCATE processcursor
What this does is turn your update query into a string, then passes the SQL contained in that string to the sp_executesql stored procedure (this is the recommended way of executing dynamic sql, rather than EXEC('foo')).
I don't think you can do it using a variable like that. You could use dynamic SQL for the update:
DECLARE #sql VARCHAR(1000)
SET #sql = 'UPDATE' + #tableName + etc..
EXEC ( #sql )
And just do this inside your cursor.
You can't execute sql dynamically like this - you need to pass a dynamically generated string into the exec function like this:
DECLARE #tblName varchar(50)
DECLARE process_cursor CURSOR FOR
SELECT source
FROM tmpTableNames
OPEN process_cursor
FETCH NEXT FROM processcursor
INTO #tblName
WHILE ##FETCH_STATUS = 0
Declare #sql varchar(5000)
Select #sql = 'UPDATE ' + #tblName +
'SET itemid = r.itemid
FROM ' + #tblName + ' v, itemref r
WHERE r.olditemid = v.itemid'
Exec #sql
FETCH NEXT FROM process_cursor
INTO #tblName
END
CLOSE processcursor
DEALLOCATE processcursor
did you try
DECLARE #tblName varchar(50)?
I would think that would do it.
I've never been successful with variable-based UPDATE statements (i.e., UPDATE #tblName), unless I captured them into a string and executed these dynamically, as in:
EXEC 'UPDATE ' + #tblName + '
SET ItemId = (SELECT r.ItemId FROM itemref r WHERE r.OldItemId = ' + #tblName + '.itemId)'
For table TheTable, this should expand to:
EXEC 'UPDATE TheTable
SET ItemId = (SELECT r.ItemId FROM itemref r WHERE r.OldItemId = TheTable.ItemId)'