It is unlikely that the cursor you are using is the cause of the delay in returning results. Most likely, the delay is due to running many select statements over possibly a large amount of data. Having said that, I likely wouldn't use the DECLARE CURSOR cur FOR ...
construct to solve this issue.
I generally approach this class of problem by generating a single dynamic SQL statement, then execute that statement using either sp_executesql()
or EXEC ()
, as in:
IF COALESCE(OBJECT_ID('dbo.TableList'), 0) <> 0
DROP TABLE dbo.TableList;
CREATE TABLE dbo.TableList
(
DatabaseName SYSNAME NOT NULL
, SchemaName SYSNAME NOT NULL
, TableName SYSNAME NOT NULL
);
INSERT INTO dbo.TableList(DatabaseName, SchemaName, TableName)
VALUES ('Database1', 'Schema1', 'Table1')
, ('Database2', 'Schema2', 'Table2');
DECLARE @cmd NVARCHAR(MAX);
SET @cmd = '';
SELECT @cmd = @cmd + CASE WHEN @cmd = '' THEN '' ELSE CHAR(13) + CHAR(10) END
+ 'SELECT ''' + tl.DatabaseName
+ '.' + tl.SchemaName
+ '.' + tl.TableName
+ ''', * '
+ 'FROM ' + QUOTENAME(tl.DatabaseName)
+ '.' + QUOTENAME(tl.SchemaName)
+ '.' + QUOTENAME(tl.TableName) + ';'
FROM dbo.TableList tl;
PRINT (@cmd);
EXEC sp_executesql @cmd;
This constructs statements required from the TableList
table, appending each statement into a variable. The variable contents are then executed using the sp_executesql
system stored procedure. This methodology can be used for a multitude of problems where you need to generate T-SQL statements based on the results of some query.
The output will be a single result set for each row in TableList
- you probably don't want to do this for more than about 50 or 100 tables since the output might become unmanageable. If you have a lot of tables, you may want to consider inserting the output into a temporary table, then running a single select
statement against that table.
If the structure of the tables listed in the TableName
column are identical, you can use a UNION ALL
to join the output into a single resultset:
SELECT @cmd = @cmd + CASE WHEN @cmd = '' THEN '' ELSE CHAR(13) + CHAR(10)
+ 'UNION ALL' + CHAR(13) + CHAR(10) END
+ 'SELECT ''' + tl.DatabaseName
+ '.' + tl.SchemaName
+ '.' + tl.TableName
+ ''', * '
+ 'FROM ' + QUOTENAME(tl.DatabaseName)
+ '.' + QUOTENAME(tl.SchemaName)
+ '.' + QUOTENAME(tl.TableName) + ';'
FROM dbo.TableList tl;
Be aware that UNION ALL
is generally much faster than UNION
since the ALL
option doesn't need to run a DISTINCT
operator over the data.
You can use the following update.
update #BlueBell set rglname = b.rglname
from #BlueBell a
inner join (
select region, rglname
from #BlueBell where rglname is not null
) b on a.region = b.region
Check your desired output here
select *
from #BlueBell
Best Answer
I would use a CTE here to provide row numbers to your table data (partitioned by the empName). That way you can update the cte, which has the advantage of actually updating the base table.
No bear in mind that because you have no ordering column there is no guarantee of which row would actually get updated (you would want more restrictive sorting conditions around this), however for a base example you can use the following.