SQL Server Execution Timeout Expired - sql-server

Is there something wrong with my code? I get an exception:
Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
I'm trying to update a dynamic table with dynamic columns depending on the searched facility of user
ALTER PROCEDURE SP_UPDATE_FACILITY
#featid int,
#facilityid int,
#updatetbl as TABLE_UPDATE_FACILITYDETAILS READONLY
AS
BEGIN
SET NOCOUNT ON;
DECLARE #tblname AS NVARCHAR(255);
SET #tblname = (SELECT dbo.FNC_Search_GetSearchTable(#facilityid));
DECLARE #key varchar(255);
DECLARE #value varchar(255);
DECLARE #MyCursor CURSOR
SET #MyCursor = CURSOR FOR
SELECT col_key, col_value FROM #updatetbl
OPEN #MyCursor
FETCH NEXT FROM #MyCursor INTO #key , #value
WHILE ##FETCH_STATUS = 0
BEGIN
IF(#key != '' and #value != '')
BEGIN
BEGIN TRY
SET #value = (CAST ( #value AS varchar(255)));
END TRY
BEGIN CATCH
SET #value = (CAST ( #value AS float));
END CATCH;
DECLARE #sSQL NVARCHAR(500);
SET #sSQL = 'UPDATE ' + QUOTENAME(#tblname) + ' SET ' + QUOTENAME(#key) + ' = #value WHERE FEATID = #featid'
EXEC sp_executesql #sSQL , N'#value VARCHAR(255), #featid INT', #key, #featid
FETCH NEXT FROM #MyCursor INTO #key, #value
END
END;
CLOSE #MyCursor ;
DEALLOCATE #MyCursor;
END
GO
Is there a way to loop through rows of table then get the values per rows of table

SQL Server does not have any "execution timeout", while the clients can set it.
If you use C#, the default Execution timeout is 30 seconds that is too small.
Of course you should investigate what your query is waiting for using sys.dm_os_waiting_tasks, but if 30 seconds are not enough to your code to complete, just change this Execution timeout value to smth else (0 = infinite)

Related

how to use variable name as table name in update statement

I have a table(Lets say'A') that contains the list of all tables in a database.I have defined a cursor that iterate through the tables name in 'A'.I want to update the table column defined in a cursor.
I have created 2 cursors.One to iterate over the tables names and other one to iterate over the column names.
DECLARE #MyCursor CURSOR;
DECLARE #MyField nvarchar(255);
BEGIN
SET #MyCursor = CURSOR FOR
select distinct Table_name from DataTable where Data <>'No'
set #a=0
OPEN #MyCursor
FETCH NEXT FROM #MyCursor
INTO #MyField
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #column_cursor CURSOR;
DECLARE #columnField nvarchar(255);
SET #column_cursor = CURSOR FOR
select Column_name from DataTable where TABLE_NAME=#MyField and Data
<>'No'
OPEN #column_cursor
FETCH NEXT FROM #column_cursor
INTO #columnField
WHILE ##FETCH_STATUS = 0
BEGIN
update #MyField set #columnField=''+#MyField+'_'+#columnField+#a
FETCH NEXT FROM #column_cursor
INTO #columnField
END;
CLOSE #column_cursor ;
DEALLOCATE #column_cursor;
FETCH NEXT FROM #MyCursor
INTO #MyField
END;
CLOSE #MyCursor ;
DEALLOCATE #MyCursor;
END;
Here in the update statement #MyField is giving error :"Must declare the table variable #MyField".
You are on good way but you can't use variable on table name place , you need to build your update command in variable and then execute dynamic sql.
You can see: Creating a dynamic sql query
in your case someting like
declare #sqlCommand varchar(max)
declare #MyField varchar(255) = 'table_name'
declare #columnField varchar(255) = 'column_NAME'
declare #columnValue varchar(255) = 'column_value'
set #sqlCommand = 'update '+ #MyField +' set '+#columnField+' = ' +#columnValue+ ' where 1=1;'
--select #sqlCommand
EXEC (#sqlCommand)

Cursorfetch: The number of variables declared in the INTO list must match that of selected columns in SQL Server 2012

I created a stored procedure that validates certain columns given a table as parameter and decided to use Cursor. But I am getting this cursor fetch error when trying to execute the stored procedure.
I already double checked the columns and it matches the number of variables in INTO list. I tried modifying the stored procedure by writing this
SELECT Lot, ItemId, PO, Status, ErrorDetails
FROM Table1
instead of
SELECT #SQLSTATEMENT
after
SET #MyCursor = CURSOR FOR
and it works fine. But I want the source table to be a parameter so this won't work for me. Any ideas?
CREATE PROCEDURE [dbo].[ValidateData]
#TABLENAME_PARAM NVARCHAR(100)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #MyCursor CURSOR;
DECLARE #CustomerLot NVARCHAR(100),
#DeviceName NVARCHAR(100),
#PO NVARCHAR(100),
#Status NVARCHAR(1),
#ErrorDetails NVARCHAR(250);
DECLARE #TABLENAME NVARCHAR(100);
DECLARE #SQLSTATEMENT AS NVARCHAR(MAX);
SELECT #TABLENAME = Quotename (TABLE_NAME)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #TABLENAME_PARAM
SET #SQLSTATEMENT = 'Select Lot, ItemId, PO, Status, ErrorDetails FROM ' + #TABLENAME + ' WHERE Status = ''N'''
BEGIN
SET #MyCursor = CURSOR FOR
SELECT #SQLSTATEMENT
OPEN #MyCursor
FETCH NEXT FROM #MyCursor INTO #CustomerLot, #DeviceName, #PO, #Status, #ErrorDetails
WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN TRAN
--some validations here
COMMIT TRAN
FETCH NEXT FROM #MyCursor INTO #CustomerLot, #DeviceName, #PO, #Status, #ErrorDetails
END;
CLOSE #MyCursor;
DEALLOCATE #MyCursor;
END
END
GO
Try this-
CREATE PROCEDURE [dbo].[ValidateData] #TABLENAME_PARAM NVARCHAR(100)
AS
BEGIN
SET NOCOUNT ON;
--DECLARE #MyCursor CURSOR;
DECLARE
#CustomerLot NVARCHAR(100),
#DeviceName NVARCHAR(100),
#PO NVARCHAR(100),
#Status NVARCHAR(1),
#ErrorDetails NVARCHAR(250);
DECLARE #TABLENAME NVARCHAR(100);
DECLARE #SQLSTATEMENT AS NVARCHAR(MAX);
SELECT #TABLENAME = Quotename (TABLE_NAME)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #TABLENAME_PARAM
SET #SQLSTATEMENT = 'DECLARE MyCursor CURSOR FOR Select Lot, ItemId, PO, Status, ErrorDetails FROM ' + #TABLENAME + ' WHERE Status = ''N'''
EXEC sp_executesql #sqlstatement
OPEN MyCursor
FETCH NEXT FROM MyCursor INTO #CustomerLot, #DeviceName, #PO, #Status, #ErrorDetails
WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN TRAN
--some validations here
COMMIT TRAN
FETCH NEXT FROM MyCursor INTO #CustomerLot, #DeviceName, #PO, #Status, #ErrorDetails
END;
CLOSE MyCursor;
DEALLOCATE MyCursor
END
END
GO

Replacing cursor with set based query

I want to find count of set of tables. The table names are values in another table.
--like
select count(*) from tablename
--tablename is obtained from
select tablename from table1
--table1 has around 171 tablenames
I was using cursor to get each table name and select count for each, but it is taking time. Can you please help how to replace cursor code with set based solution?
Below is my cursor code
SET NOCOUNT ON;
if( OBJECT_ID('tempdb..#temptablenew') IS NOT NULL )
BEGIN
DROP table #temptablenew
END
select * into #temptablenew from table1
declare #srccount int
declare #tablename nvarchar(max);
declare #q2 nvarchar(max);
declare #id int;
declare my_cursor cursor
local static read_only forward_only
for
select id,tablename from #temptablenew
open my_cursor
fetch next from my_cursor
into #id,#tablename
while ##fetch_status = 0
begin
set #q2 =N'select #srccount= count(*) from '+#tablename+' with (nolock)';
execute sp_executesql #q2,#PARAMS = N'#srccount INT OUTPUT',
#srccount = #srccount OUTPUT
select #srccount,#id,#tablename
fetch next from my_cursor
into #id,#tablename
end
close my_cursor;
deallocate my_cursor;
Thanks in advance
Try this,
SET NOCOUNT ON;
declare #q2 nvarchar(max) = '';
SELECT #q2 = #q2 + 'SELECT COUNT(*) AS cnt, ''' + tablename + ''' AS TableName FROM ' + tablename + ' (NOLOCK); '
FROM table1
--Print #q2
execute sp_executesql #q2

T-SQL cursor for linked server INSERT SELECT

I'm trying to get this cursor loop to work, so I could copy data from linked server to another server. However it seems that the cursor is in a loop and does nothing. What am I doing wrong?
/* For testing purposes I'm fetching data from
1 company only. The result should be one row.*/
DECLARE #tmp_key VARCHAR(14)
DECLARE #db cursor
DECLARE #sql NVARCHAR(MAX)
SET #db = CURSOR FOR
SELECT [CompanyId] FROM [Test].[dbo].[Company] WHERE [CompanyId] = '0001'
SET #sql = N'INSERT INTO [Stagingarea].[dbo].[Cominfo]
SELECT
convert(nvarchar(100),[Nro])
,convert(nvarchar(100),'+#tmp_key+' )
FROM [Linked_server_name].TK'+#tmp_key+'.[dbo].[cominfo]
where [rule1] <> 0 and acc = 1777';
OPEN #db
FETCH NEXT FROM #db INTO #tmp_key
while (##fetch_status = 0)
begin
EXEC sp_sqlexec #sql
end;
CLOSE #db
DEALLOCATE #db
You should put the dynamic SQL inside the WHILE loop. Make sure to call FETCH NEXT inside to avoid infinite loop.
DECLARE #tmp_key VARCHAR(14)
DECLARE #db cursor
DECLARE #sql NVARCHAR(MAX)
SET #db = CURSOR FOR
SELECT [CompanyId] FROM [Test].[dbo].[Company] WHERE [CompanyId] = '0001'
OPEN #db
FETCH NEXT FROM #db INTO #tmp_key
WHILE(##FETCH_STATUS = 0) BEGIN
SET #sql = N'INSERT INTO [Stagingarea].[dbo].[Cominfo]
SELECT
CONVERT(NVARCHAR(100), [Nro])
,CONVERT(NVARCHAR(100),' + #tmp_key +')
FROM [Linked_server_name].TK' + #tmp_key + '.[dbo].[cominfo]
WHERE [rule1] <> 0 AND acc = 1777';
EXEC sp_sqlexec #sql
FETCH NEXT FROM #db INTO #tmp_key
END;
CLOSE #db
DEALLOCATE #db

Can I apply an update statement to multiple databases at the same time?

Say I want to run the following:
update users set age = 10
on databases:
db1, db2, db3
All on the same server, I want to loop through and perform the same action.
Currently I am doing this manually using management studio via the dropdown.
Hoping there is a better way.
You could probably do it with dynamic SQL. Something like so:
create table #dbs (db_name sysname not null)
insert into #dbs values ('db1'),('db2'),('db3')
declare curs cursor for
select db_name from #dbs
declare #db sysname, #sql nvarchar(max)
open curs
while(1=1)
begin
fetch next from curs into #db
if (##fetch_status <> 0)
break
set #sql = 'update ' + quotename(#db) + '.dbo.users set age = 10'
exec(#sql)
end
close curs
deallocate curs
drop table #dbs
Not sure about doing it 'dynamically', i.e. a FOR-EACH style loop on all the databases in a server, but this should work:
USE db1
update users set age = 10
GO
USE db2
update users set age = 10
GO
USE db3
update users set age = 10
Designate a server as a central management server and then add the other servers to the server group. Then you can run the update on all databases within the group. http://msdn.microsoft.com/en-us/library/bb934126.aspx
use [WWAUTHxxx__] -- a db containing active databases.
set nocount on
declare #Catalog as nvarchar(32)
declare #LibraryName as varchar(255)
declare #dbtable as varchar(50)
declare #retval as nvarchar(50)
declare #sSQL as nvarchar(max)
declare #parmdef as nvarchar(500)
declare #retvalout as nvarchar(50)
Declare Library_Cursor Cursor for
select top(1000) xCatalog, xLibraryName
from Active_DBs
order by xcatalog
Open Library_Cursor;
Fetch Next from Library_Cursor into #Catalog, #LibraryName
while ##Fetch_status = 0
begin
set #dbTable = #Catalog + '.dbo.las_circperiods'
set #ParmDef = N'#retvalOUT int OUTPUT';
set #sSQL = N'Select #retvalout = count(*) from ' + #dbtable
+ ' where xlastcircdate is null'
exec sp_executesql #ssql,#parmdef,#retvalout=#retval output
if #retval > 0 -- check/print Sql and then activate.
-- I like checking to see the potentially affected databases.
begin
print #Catalog + ',' + #LibraryName + ',' + #retval
set #ssql = N'update ' + #dbTable
+ ' set xlastcircdate = '''' '
+ ' where xlastcircdate is null'
-- print #ssql -- View what you might will do
exec sp_executesql #ssql -- Do it.
end
Fetch Next from Library_Cursor into #Catalog, #LibraryName
end;
close Library_cursor
Deallocate Library_cursor

Resources