Stored Procedure That Return Different Table According To Parameter - sql

I want to write a stored procedure that takes #FirmId as a parameter and I will use the related table according to this parameter.
What I want to obtain (but I don't want to use) is something like that:
CREATE PROCEDURE spFirmDetailGetByFirmId
#FirmId AS INT
AS
BEGIN
IF #FirmId = 1
SELECT * FROM Firm1
ELSE IF #FirmId = 2
SELECT * FROM Firm2
.
.
.
.
ELSE IF #FirmId = 1000
SELECT * FROM Firm1000
END
And also I don't want to create query string and then EXEC it, something like that in the fallowing code block. Because the real query is too complex and it will be very hard to manage if I use this option.
CREATE PROCEDURE spFirmDetailGetByFirmId
#FirmId AS INT
AS
BEGIN
DECLARE #Query AS NVARCHAR(MAX) = 'SELECT * FROM Firm'
SET #Query = #Query + CAST(#FirmId AS NVARCHAR(10))
EXEC(#Query)
END
Is there any other option?
Thanks.

I take your Yes the tables are identical and will be kept identical to suggest two approaches:
DECLARE #Firm VARCHAR(10)='Firm3';
SELECT * FROM Firm1 WHERE #Firm='Firm1'
UNION ALL
SELECT * FROM Firm2 WHERE #Firm='Firm2'
UNION ALL
SELECT * FROM Firm3 WHERE #Firm='Firm3'
[...]
UNION ALL
SELECT * FROM Firm1000 WHERE #Firm='Firm1000'
The second is:
DECLARE #query NVARCHAR(MAX)='SELECT * FROM ####';
SET #query=REPLACE(#query,'####',#Firm);
EXEC (#query)
The second could be used with a VIEW (in place of the #query), where you could read the VIEW's definition into the variable and create an ALTER VIEW-statement dynamically... Your procedure would call the same VIEW (but this would crash with parallel calls!)

This code can by use in a stored procedure to automatic create the view, every time you need to add columns
declare #tableId int
declare #columns varchar(max)
declare #tablesCount int
declare #tableName varchar(255)
declare #query varchar(255)
declare #id int
declare #result nvarchar(max)
set #columns = ''
set #tableName = 'Firm'
set #id = 1
set #result = ''
--Base table
select #tableId = object_id from sys.tables where name =#tableName
--Count how many table with the 'same name'
select #tablesCount= count(*) from sys.tables where name like #tableName+'%'
--Build Columns to add in the view
select #columns =#columns+name+', 'from Sys.columns where object_id = #tableId
--Drop View
set #result = 'Drop view vw_'+#tableName
exec sp_executesql #result
set #result=''
while(#id<=#tablesCount)
Begin
declare #idVarchar varchar(10)
set #idVarchar = cast(#id as varchar(10))
set #result =#result+'Select '+#columns+#idVarchar+' as FirmId from '+#tableName+#idVarchar
+'
Union all
'
set #id =#id+1
End
set #result = substring(#result, 1, len(#result)-12)
set #result='Create view vw_'+#tableName+' as
'+#result
exec sp_executesql #result
There is a another choice to this, you can also use sp_helpText to get the current definition of the view and append only add new table identifier

Related

not able to use sp_executesql command

I need to execute below query
SELECT *, IDENTITY( int ) AS IDColumn INTO #SmootheningTable FROM #TableName
where #SmootheningTable is temporary table
and #TableName is name of table
I need to use command either EXEC or sp_executesql to execute.
If I use EXEC, I wont be able to use #SmootheningTable in later portion of my stored procedure.
And while trying sp_executesql, I am getting error stating #statement error.
How can I use sp_executesql for above given query.
Or is there any other way to execute?
this is the query I am using
DECLARE #TablePlaceHolder VARCHAR(50)='';
DECLARE #SmootheningQuery NVARCHAR(max) = 'SELECT *, IDENTITY( int ) AS IDColumn INTO #SmootheningTable FROM #TablePlaceHolder';
EXEC sp_executesql #SmootheningQuery, N'#TablePlaceHolder varchar(50)', #PlanDetailTempTableName
and i am getting below error
Must declare the table variable "#TablePlaceHolder".
Thanks in advance
There are two issues in your code:-
First : Putting the variable name inside the string, put in out like next:-
instead of this line:-
DECLARE #SmootheningQuery NVARCHAR(max) = 'SELECT *, IDENTITY( int ) AS
IDColumn INTO #SmootheningTable FROM #TablePlaceHolder';
Type this line:-
DECLARE #SmootheningQuery NVARCHAR(max) = 'SELECT *, IDENTITY( int ) AS
IDColumn INTO #SmootheningTable FROM ' + #TablePlaceHolder;
Second: Don't use local temp table within sp_executeSql,
The Local temporary table [with one hash # ] is visible in current session only, use global temporary tables instead [with two hashes ## ] are visible in all sessions,
So instead of
#SmootheningTable
Type
##SmootheningTable
Demo (All Code): -
Create table MyTable (id int , name nvarchar(100))
go
insert into MyTable values (1, 'Ahmed');
insert into MyTable values (2, 'Abdelqader');
go
declare
#TableName varchar(50),
#MyQuery nvarchar(200)
set #TableName = 'MyTable'
set #MyQuery = 'select * Into ##MYTempTable From ' + #TableName
exec sp_executesql #MyQuery
select * from ##MYTempTable
Result:-
id name
1 Ahmed
2 Abdelqader
Please Try This,
CREATE PROC usp_SmootheningTable
AS
BEGIN
SELECT *, IDENTITY( int ) AS IDColumn INTO #SmootheningTable FROM
TableName
SELECT * FROM #SmootheningTable
END
GO
Please try this out
CREATE TABLE #Temp
(
Columns
)
DECLARE #SQL NVARCHAR(MAX)
DECLARE #TableName VARCHAR(MAX)
SET #TableName = 'TableName'
SET #SQL = 'SELECT TOP 10 * FROM '+#TableName
INSERT INTO #Temp
EXEC SP_EXECUTESQL #SQL
SELECT * FROM #Temp

How to Execute script in multiple databases at once

In Sql Server
I have sample script
Declare #V table (name varchar(100))
INSERT INTO #V(name)
select name from sys.databases where database_id > 6
select NAME from #V
If I execute this Script I get the user databases list
In my instance I have below Databases :
DatabaseName
mohan
Ravi
How can I dynamically append the Database names to below script and execute the script in below Databases
Declare #V table (ID INT,name varchar(100))
INSERT INTO #V(Id,name)
select ROW_NUMBER()OVER(ORDER BY NAME),name from sys.databases where database_id > 6
DECLARE #LoopCounter INT , #MaxId INT,
#Name NVARCHAR(100)
SELECT #LoopCounter = min(id) , #MaxId = max(Id)
FROM #V
WHILE(#LoopCounter IS NOT NULL
AND #LoopCounter <= #MaxId)
BEGIN
SELECT #Name = Name
FROM #V WHERE Id = #LoopCounter
PRINT #Name
SET #LoopCounter = #LoopCounter + 1
END
DECLARE #DatabaseName VARCHAR(50) = #Name
, #SQL NVARCHAR(MAX);
SET #SQL = N'USE ' + QUOTENAME(#DatabaseName)
+'CREATE TABLE T(ID INT)';
--PRINT(#SQL);
EXECUTE(#SQL);
So in all user databases Table will be created . I have tried with sp_msforeachdb
script :
DECLARE #Sql AS VARCHAR(4000)
SET #Sql = 'IF ''?'' NOT IN (''master'',''tempdb'',''model'',''msdb'',''ReportServer'',''ReportServerTempDB'')
EXECUTE ('' USE [?] CREATE TABLE T (ID INT)'')'
EXEC sp_MSforeachdb #command1 = #Sql
But I'm looking for looping script .How to append those names to the Script
No need for a loop here. You can generate the entire statement in one pass. This query populates a var that contains multiple USE and CREATE TABLE statements:
DECLARE #Qry NVARCHAR(MAX) = '';
-- Build dynamic SQL statement here.
-- 1 Row returned per target database .
SELECT
#Qry +=
'
USE' + QUOTENAME(Name) + ';
CREATE TABLE T
(
ID INT
)
;
'
FROM
sys.Databases
WHERE
database_id > 6
;
-- Remove comments from last line when happy with query.
PRINT #Qry
--EXECUTE sp_ExecuteSQL #Qry
Returns
USE [X];
CREATE TABLE T
(
ID INT
)
;
USE [Y];
CREATE TABLE T
(
ID INT
)
;
...

How to store a dynamic SQL result in a variable in T-SQL?

I have a stored procedure which takes 'table name' as parameter. I want to store my 'exec' results to a variable and display using that variable.
Here is my T-SQL stored procedure..
create procedure DisplayTable( #tab varchar(30))
as
begin
Declare #Query VARCHAR(30)
set #Query='select * from ' +#tab
EXEC (#Query)
END
I want to do something like this..
SET #QueryResult = EXEC (#Query)
select #QueryResult
How do i achieve this.. Please help.. I am a beginner..
You can use XML for that. Just add e.g. "FOR XML AUTO" at the end of your SELECT. It's not tabular format, but at least it fulfills your requirement, and allows you to query and even update the result. XML support in SQL Server is very strong, just make yourself acquainted with the topic. You can start here: http://technet.microsoft.com/en-us/library/ms178107.aspx
alter procedure DisplayTable(
#tab varchar(30)
,#query varchar(max) output
)
as
BEGIN
Declare #execution varchar(max) = 'select * from ' +#tab
declare #tempStructure as table (
pk_id int identity
,ColumnName varchar(max)
,ColumnDataType varchar(max)
)
insert into
#tempStructure
select
COLUMN_NAME
,DATA_TYPE
from
INFORMATION_SCHEMA.columns
where TABLE_NAME= #tab
EXEC(#execution)
declare #ColumnCount int = (SELECT count(*) from #tempStructure)
declare #counter int = 1
while #counter <= #ColumnCount
BEGIN
IF #counter = 1
BEGIN
set #query = (SELECT ColumnName + ' ' + ColumnDataType FROM #tempStructure where pk_id= #counter)
END
IF #counter <> 1
BEGIN
set #query = #query + (SELECT ',' + ColumnName + ' ' + ColumnDataType FROM #tempStructure where #counter = pk_id)
END
set #counter = #counter + 1
END
END
When you execute the SP, you'll now get a return of the structure of the table you want.
This should hopefully get you moving.
If you want the table CONTENTS included, create yourself a loop for the entries, and append them to the #query parameter.
Remember to delimit the #query, else when you read it later on, you will not be able to restructure your table.
First of all you have to understand that you can't just store the value of a SELECTon a table in simple variable. It has to be TABLE variable which can store the value of a SELECTquery.
Try the below:
select 'name1' name, 12 age
into MyTable
union select 'name2', 15 union
select 'name3', 19
--declaring the table variable and selecting out of it..
declare #QueryResult table(name varchar(30), age int)
insert #QueryResult exec DisplayTable 'MyTable'
select * from #QueryResult
Hope this helps!

adding a table as parameter in a query string in a stored procedure

I have the following query :
ALTER procedure [dbo].[jk_insertAllLocation]
#locationTbl as locationTable readonly,
#TableName varchar(100)
as
declare #tbl as locationTable,#sql varchar(max)
begin
set #sql = 'insert into ' + #TableName +'(location_id,name,address,latitude,longitude,distance,state,sub_cat,id_cat,icon_link,checkinsCount,IDSearch)
select * from ' + #locationTbl
exec sp_executesql #sql
end
I need to pass a table and a table name as parameter and I need to insert in the table name (#TableName) passed as parameter all the data in the table (#locationTbl) passed as parameter
but I know that I cannot concatenate the table (#locationTbl) in the query ...
so how can I fix this?
You can use temp tables (Temporary tables section on link):
ALTER procedure [dbo].[jk_insertAllLocation]
#locationTbl as locationTable readonly,
#TableName varchar(100)
as
begin
declare #tbl as locationTable,#sql varchar(max)
if object_id('#_tmp_location_table') is not null drop table #_tmp_location_table
select * into #_tmp_location_table from #locationTbl
set #sql = 'insert into ' + #TableName + '(location_id,name,address,latitude,longitude,distance,state,sub_cat,id_cat,icon_link,checkinsCount,IDSearch) select * from #_tmp_location_table'
exec sp_executesql #sql
end

Pass a TABLE variable to sp_executesql

I'm trying to pass a TABLE variable to the sp_executesql procedure:
DECLARE #params NVARCHAR(MAX)
SET #params = '#workingData TABLE ( col1 VARCHAR(20),
col2 VARCHAR(50) )'
EXEC sp_executesql #sql, #params, #workingData
I get the error:
Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'TABLE'.
I tried omitting the column specification after 'TABLE'. I also tried to declare the table as a variable inside the dynamic SQL. But no luck...
Seems to me that TABLE variables aren't allowed to be passed as parameters in this procedure?. BTW: I'm running MSSQL2008 R2.
I'm not interested in using a local temp table like #workingData because I load the working data from another procedure:
INSERT INTO #workingData
EXEC myProc #param1, #param2
Which I cannot do directly into a temp varaible (right?)...
Any help appreciated!
If you are using SQL Server 2008, to pass a table variable to a stored procedure you must first define the table type, e.g.:
CREATE TYPE SalesHistoryTableType AS TABLE
(
[Product] [varchar](10) NULL,
[SaleDate] [datetime] NULL,
[SalePrice] [money] NULL
)
GO
or use an existing table type stored in the database.
Use this query to locate existing table types
SELECT * FROM sys.table_types
To use in an stored procedure, declare an input variable to be the table:
CREATE PROCEDURE usp_myproc
(
#TableVariable SalesHistoryTableType READONLY
)
AS BEGIN
--Do stuff
END
GO
Populate the table variable before passing to the stored procedure:
DECLARE #DataTable AS SalesHistoryTableType
INSERT INTO #DataTable
SELECT * FROM (Some data)
Call the stored procedure:
EXECUTE usp_myproc
#TableVariable = #DataTable
Further discussions here.
OK, this will get me what I want, but surely isn't pretty:
DECLARE #workingData TABLE ( col1 VARCHAR(20),
col2 VARCHAR(20) )
INSERT INTO #workingData
EXEC myProc
/* Unfortunately table variables are outside scope
for the dynamic SQL later run. We copy the
table to a temp table.
The table variable is needed to extract data directly
from the strored procedure call above...
*/
SELECT *
INTO #workingData
FROM #workingData
DECLARE #sql NVARCHAR(MAX)
SET #sql = 'SELECT * FROM #workingData'
EXEC sp_executesql #sql
There must be a better way to pass this temporary resultset into sp_executesql!?
Regards
Alex
While this may not directly answer your question, it should solve your issue overall.
You can indeed capture the results of a Stored Procedure execution into a temporary table:
INSERT INTO #workingData
EXEC myProc
So change your code to look like the following:
CREATE TABLE #workingData ( col1 VARCHAR(20),
col2 VARCHAR(20) )
INSERT INTO #workingData
EXEC myProc
DECLARE #sql NVARCHAR(MAX)
SET #sql = 'SELECT * FROM #workingData'
EXEC sp_executesql #sql
Regards,
Tim
Alter PROCEDURE sp_table_getcount
#tblname nvarchar(50) ,
#totalrow int output
AS
BEGIN
Declare #params nvarchar(1000)
Declare #sql nvarchar(1000)
set #sql = N'Select #cnt= count(*) From #tbl'
set #params = N'#tbl nvarchar(50) , #cnt int OUTPUT'
Exec sp_executesql #sql , #params ,#tbl=#tblname , #cnt = #totalrow OUTPUT
END
GO
Please note that the above code will not work as table as a object is out of the scope.It will give you the error: must declare table variable.In order to work around we can do the following.
Alter PROCEDURE sp_table_getcount
#tblname nvarchar(50) ,
#totalrow int output
AS
BEGIN
Declare #params nvarchar(1000)
Declare #sql nvarchar(1000)
set #sql = N'Select #cnt= count(*) From dbo.' + #tblname
set #params = N'#cnt int OUTPUT'
Exec sp_executesql #sql , #params , #cnt = #totalrow OUTPUT
END
GO
So-called TableType is tricky. #Alex version should work. However, to simplify and faster performance, go check sys.tables for matching table name while not compromise security and performance.
Here it is
create proc [dbo].Test11
#t1 AS nvarchar(250), #t2 nvarchar(250)
AS
BEGIN
SET nocount ON;
DECLARE #query AS nvarchar(MAX)
if exists (select * from sys.tables where name = #t1) and
exists (select * from sys.tables where name = #t2)
begin
SET #query = N'select * FROM '+ #t1 + N' join ' + #t2 + N' ON ...' ;
select 'Safe and fast'
print #query
exec sp_executesql #query
end
else
select 'Bad, no way Jose.'
SET nocount OFF;
END
GO