Sql-server – Query All Databases Listed In Table

sql serversql-server-2008-r2t-sql

I have been using a cursor to get my results, but it is taking an extended period of time to return my result set. I am hoping to find a way to QUICKLY get the results returned (if at all possible). Here is my data structure with garbage DDL.

1st problem is each employee has there own table. I understand this is a major design flaw, and we are quickly working to remedy this, but I need an alternative until all elements have been updated. All 3 tables geoffrey, jorge, mitch all have the same structure, and I have attached sample DDL for geoffrey, & jorge and below is a sample query that shows what I need to query from each of the two tables.

Greatly appreciate any and all help on how to achieve this result!

Create Table #ReviewDB
(
  [TableName] varchar(500)
  ,[ServerDBTable] varchar(MAX)
)
Insert Into #ReviewDB VALUES
('geoffrey', 'beans.franks.dbo.geoffrey')
,('jorge', 'smallpox.virus.dbo.jorge')
,('mitch', 'mosquito.insect.dbo.mitch')
Create Table #geoffrey
(
  recordID int IDENTITY(1,1) PRIMARY KEY
  ,firstname varchar(500)
  ,lastname varchar(500)
  ,address varchar(500)
  ,city varchar(500)
  ,state varchar(500)
  ,zip varchar(500)
  ,phone varchar(500)
  ,itemsold varchar(500)
  ,saledate datetime
  ,managerapproved varchar(500)
)
Insert Into #geoffrey VALUES
('manny', 'ramirez', '1111111 aoaswdfrljkasdf ', 'topaz', 'mn', '1111', '9995552222', 'sofa', '01/21/2016', '')
,('hi', 'ho', '2323 aoaswdfrljkasdf ', 'topaz', 'mn', '1111', '6662229888', 'chair', '02/21/2016', '')
,('ee', 'aa', '4646 aoaswdfrljkasdf ', 'topaz', 'mn', '1111', '3332221919', 'ottoman', '01/21/2016', '')
Create Table #jorge
(
  recordID int IDENTITY(1,1) PRIMARY KEY
  ,firstname varchar(500)
  ,lastname varchar(500)
  ,address varchar(500)
  ,city varchar(500)
  ,state varchar(500)
  ,zip varchar(500)
  ,phone varchar(500)
  ,itemsold varchar(500)
  ,saledate datetime
  ,managerapproved varchar(500)
)
Insert Into #jorge VALUES
('aa', 'bb', '1111111 c street ', 'holt', 'tn', '2222', '1113334444', 'sofa', '01/21/2016', '')
,('cc', 'ddo', '2323 b street ', 'holt', 'tn', '2222', '8889997788', 'chair', '02/21/2016', '')
,('mm', 'rr', '4646 e street ', 'holt', 'tn', '2222', '8889998877', 'ottoman', '03/21/2016', '')
Create Table #managerrevieweddata
(
  ID int IDENTITY(1,1) PRIMARY KEY
  ,recordID int
  ,dbname varchar(500)
  ,managernotes text
  ,regionalmanager varchar(500)
  ,districtmanager varchar(500)
  ,incentiveitem varchar(500)
)
Insert Into #managerrevieweddata VALUES
('1', 'geoffrey', 'Valid sale, remind to offer upsell next time.', 'Regional Manager', 'District Manager', 'No')
,('2', 'jorge', 'Review with salesman', 'Regional Manager', 'District Manager', 'NO')

And here is a query that shows what I want my desired output to be.

I need a way to query each serverdbtable in #ReviewDB and return the below select statement

Declare @saledate datetime
Set @saledate = '03/21/2016'

Select a.firstname, a.lastname, a.address, a.city, 
a.state, a.zip, a.phone,   a.itemsold, a.saledate,
b.dbname, b.managernotes, b.regionalmanager, 
b.districtmanager, b.incentiveitem
FROM #ReviewDB.ServerDBTable a
INNER JOIN #managerrevieweddata b
ON a.recordID = b.recordID
and a.saledate = @saledate

Best Answer

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.