The Issue
I recently participated in this question about creating a Dynamic SQL script, and on review I found that a stored procedure will also do the trick.
The user has indicated that he has a table that stores the database objects name from a Source Table. That data will be used in order to generate a dynamic Select query.
Say we have the following data in the Source Table:
Also say that the user is passing a DatasourceID with value of 1.
What we want is a simple Select query based on the DB_Name, Table_Name and Fields indicated in that particular record. In this case, the following query should be returned:
SELECT [Invoice Number], [Order Number], [Order Number Line], [Cost] FROM [RC2].[dbo].[TableA]
This is similar for DatasourceID with value of 2, the following SQL statement will be returned:
SELECT [MyText0], [MyText] FROM [RC3].[dbo].[Test]
Points to check
Proposed Resolution
The script posted should be workable for MSSQL 2008 R2 and above.
This can be resolved by creating a Stored Procedure which can dynamically return different table's data based on the passing in a different parameter. In order to do so, we would need to execute the following steps.
1. Create the database structure for source table
USE [RC] GO IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[SourceTable]') AND type in (N'U')) DROP TABLE [dbo].[SourceTable] GO CREATE TABLE [dbo].[SourceTable]( [DatasourceID] [int] IDENTITY(1,1) NOT NULL, [DB_Name] [varchar](20) NULL, [TableName] [varchar](20) NULL, [Field1] [varchar](20) NULL, [Field2] [varchar](20) NULL, [Field3] [varchar](20) NULL, [Field4] [varchar](20) NULL, [Field5] [varchar](20) NULL, CONSTRAINT [PK_SourceTable] PRIMARY KEY CLUSTERED ( [DatasourceID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO
2. Create some test tables in different schemas
for example:
USE [RC2] GO IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TableA]') AND type in (N'U')) DROP TABLE [dbo].[TableA] GO CREATE TABLE [dbo].[TableA]( [Invoice Number] [varchar](50) NULL, [Order Number] [varchar](50) NULL, [Order Number Line] [varchar](50) NULL, [Cost] [money] NULL ) ON [PRIMARY] GO USE [RC3] GO IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Test]') AND type in (N'U')) DROP TABLE [dbo].[Test] GO CREATE TABLE [dbo].[Test]( [ID] [int] IDENTITY(1,1) NOT NULL, [MyText0] [varchar](50) NULL, [MyText] [nvarchar](50) NULL, CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO
3. Insert some test data into source table
USE [RC] GO INSERT INTO SourceTable ([DB_Name], [TableName], [Field1], [Field2], [Field3], [Field4], [Field5]) VALUES ('[RC2]', '[dbo].[TableA]', '[Invoice Number]', '[Order Number]', '[Order Number Line]', '[Cost]', NULL), ('[RC3]', '[dbo].[Test]', '[MyText0]', '[MyText]', NULL, NULL, NULL); GO
4. Insert some test data of targeted tables
USE [RC2] GO INSERT INTO TableA ([Invoice Number], [Order Number], [Order Number Line], [Cost]) VALUES ('I00001', 'O12345', 'Line1', 250.50), ('I00002', 'O22222', 'Line2', 100.30), ('I00003', 'O33333', 'Line3', 420.20); GO USE [RC3] GO INSERT INTO Test ([MyText0], [MyText]) VALUES ('I00001', 'testing 1'), ('I00002', 'testing 2'), ('I00003', 'testing 3'), ('I00004', 'testing 4'), ('I00001', 'testing 5'), ('I00001', 'testing 6'); GO
Now we have the following data in these tables in different schemas
SELECT * FROM [RC].[dbo].[SourceTable]
Figure 1 - Table Schema Results
SELECT * FROM [RC2].[dbo].[TableA]
Figure 2 - Sample Result Set
SELECT * FROM [RC3].[dbo].[Test]
Figure 3 - Sample Result Set
5. Create a Stored Procedure to accept a parameter and return the relevant data
USE [RC] GO IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[getTable]') AND type in (N'P', N'PC')) DROP PROCEDURE [dbo].[getTable] GO CREATE PROCEDURE [dbo].[getTable] @DatasourceID INT AS BEGIN DECLARE @DB_Name VARCHAR(20), @TableName VARCHAR(20), @Field1 VARCHAR(20), @Field2 VARCHAR(20), @Field3 VARCHAR(20), @Field4 VARCHAR(20), @Field5 VARCHAR(20), @SQL NVARCHAR(500) SET NOCOUNT ON IF EXISTS(SELECT * FROM [SourceTable] WHERE DatasourceID = @DatasourceID) BEGIN SELECT @DB_Name = [DB_Name], @TableName = [TableName], @Field1 = Field1, @Field2 = Field2, @Field3 = Field3, @Field4 = Field4, @Field5 = Field5 FROM [SourceTable] WHERE DatasourceID = @DatasourceID SET @SQL = '' IF @Field1 IS NOT NULL SET @SQL = @SQL + @Field1 + ', ' IF @Field2 IS NOT NULL SET @SQL = @SQL + @Field2 + ', ' IF @Field3 IS NOT NULL SET @SQL = @SQL + @Field3 + ', ' IF @Field4 IS NOT NULL SET @SQL = @SQL + @Field4 + ', ' IF @Field5 IS NOT NULL SET @SQL = @SQL + @Field5 + ', ' SET @SQL = 'SELECT ' + SUBSTRING(@SQL, 1, LEN(@SQL) - 1) + ' FROM ' + @DB_Name + '.' + @TableName PRINT @SQL EXEC sp_executesql @SQL END ELSE PRINT 'No Record Matched' END GO
6. Execute the Stored Procedure
Run the following SQL:
EXEC [RC].dbo.getTable 1
The results below:
Figure 4 - (this is exactly the same as what is returned by using a Select statement indicated in Figure 2 above)
EXEC [RC].dbo.getTable 2
The results below:
Figure 5 - (this is exactly the same as what is returned by using a Select statement as indicated in Image 3 above)
7. Join the results returned from the Stored Procedure with other tables
First we need to declare a table variable, we can also define a temporary table if necessary. In general, both ways work.
DECLARE @anotherTable1 TABLE ( field1 NVARCHAR(MAX), field2 NVARCHAR(MAX), field3 NVARCHAR(MAX), field4 NVARCHAR(MAX) )
When you know the exact data type of the expected result, you may change the NVARCHAR(MAX) to that expected data type.
Then Insert the results of the Stored Procedure into the table variable
INSERT INTO @anotherTable1 EXEC [RC].dbo.getTable 1
Now do the same for another variable
DECLARE @anotherTable2 TABLE ( field1 NVARCHAR(MAX), field2 NVARCHAR(MAX) ) INSERT INTO @anotherTable2 EXEC [RC].dbo.getTable 2
8. The whole process
Now as a whole (as what indicated in Step 7), we do some checking and make sure these are working
DECLARE @anotherTable1 TABLE ( field1 NVARCHAR(MAX), field2 NVARCHAR(MAX), field3 NVARCHAR(MAX), field4 NVARCHAR(MAX) ) INSERT INTO @anotherTable1 EXEC [RC].dbo.getTable 1 DECLARE @anotherTable2 TABLE ( field1 NVARCHAR(MAX), field2 NVARCHAR(MAX) ) INSERT INTO @anotherTable2 EXEC [RC].dbo.getTable 2 SELECT * FROM @anotherTable1 SELECT * FROM @anotherTable2 SELECT a.field1, a.field2, a.field3, a.field4, count(b.field1) cnt FROM @anotherTable1 a INNER JOIN @anotherTable2 b ON a.field1 = b.field1 GROUP BY a.field1, a.field2, a.field3, a.field4
The results below:
Figure 6 - Final Result Set
Follow Up
Some questions that may arise:
1. Can we use the same approach by using a Table-Valued Function instead?
2. Can we adding the Condition to this Stored Procedure?
I may write another article to address the questions mentioned above.
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (0)