Using EXEC inside SELECT statement in SQL Server - sql

I need to use exec inside of select clause. The query for the exec is created according to the columns of the table to on which select clause if used. What i want to do is something like following:
SELECT distinct
MTMain.[TableName],
MTMain.[TableFKey],
(select IsActive (exec GetStringForIsActive MTMain.[TableName],MTMain.[TableFKey]))
FROM
[MasterTableForLanguage] MTMain
Here, GetStringForIsActive is the stored procedure I want to execute for every row selected from MasterTableForLanguage.
The stored procedure will use EXEC to execute the following string
select IsActive from [TableName] where PKID= cast([TableFKey] as int)
TableName and TableFKey will be inputs of the stored procedure.

If you can modify your Stored Procedure GetStringForIsActive to return TableName, TableFKey and IsActive, you can use a cursor to get execute it for each row and add the results to a temp table.
ie:
exec GetStringForIsActive 'TableName', 'TableFKey'
returns
select [TableName], [TableFKey], IsActive from [TableName] where PKID= cast([TableFKey] as int)
The code would be like this:
declare #TableName nvarchar(50)
declare #TableFKey nvarchar(50)
declare #Results table (TableName nvarchar(50), TableFKey nvarchar(50), IsActive bit)
declare TableCursor cursor fast_forward for
select TableName, TableFKey from MasterTableForLanguage
open TableCursor
fetch next from TableCursor into #TableName, #TableFKey
if ##FETCH_STATUS <> -1
print 'MasterTableForLanguage check'
while (##FETCH_STATUS <> -1)
begin
insert into #Results
exec GetStringForIsActive #TableName, #TableFKey
fetch next from TableCursor into #TableName, #TableFKey
end
close TaleCursor
deallocate TableCursor
select * from #Results

use Functions instead of Stored procedures in SELECT clause.
Edited:
create that function
CREATE FUNCTION function1 (#TableName nvarchar(10),#TableFKey nvarchar(10))
RETURNS nvarchar(100) AS
BEGIN
-- do whatever here
END
then
SELECT distinct
MTMain.[TableName],
MTMain.[TableFKey],
function1(MTMain.[TableName],MTMain.[TableFKey])
FROM
[MasterTableForLanguage] MTMain
Does this make sense?

Well, I think to answer the full question, I don't believe a stored procedure would EXEC a SELECT statement, it would simply perform the SELECT.
You EXEC your current proc and pass it vars, and it returns a value BASED ON the select statement it runs. It's not EXEC'ing that statement, simply performing a select. I have several stored procs I use daily in some SQL agent processes, they all perform selects to query various tables, and none of them call an EXEC to perform those actions. This is my own example:
CREATE PROCEDURE [myproc]
#job_ident INT
AS
BEGIN
SET NOCOUNT ON;
...
SELECT TOP(1) #filter_type = filter_type FROM [place] WHERE [ident] = #job_ident
...
END
As mentioned previously, the most effective way to perform your query would be to perform that select inside a function, something similar to this I think will do:
CREATE FUNCTION ThisFunction (
#TableName nvarchar(10),
#TableFKey nvarchar(10)
)
RETURNS nvarchar(100)
AS
BEGIN
RETURN
(
select IsActive from [TableName] where PKID= cast([TableFKey] as int)
)
END
You could then do exactly as you want...
SELECT distinct
MTMain.[TableName],
MTMain.[TableFKey],
ThisFunction(MTMain.[TableName],MTMain.[TableFKey])
FROM
[MasterTableForLanguage] MTMain

Related

T-SQL Execute from a stored procedure

I am trying to build an SQL inside a stored procedure and execute it using
EXEC sp_executesql
Now I defined a local table and tried to pass it in need to pass it in
CREATE TYPE mytabletypeAS TABLE (
StartDate DATETIME,
EndDate DATETIME,
Amount MONEY,
AccountId INT
);
The following happens in my stored procedure, what I am trying to do is to return the output produced by EXEC sp_executesql:
CREATE PROCEDURE attributevalues.sp_EvalClearingNetSpend
AS
BEGIN
DECLARE #OutPutTable AS mytabletype;
DECLARE #Sql AS NVARCHAR(MAX);
SET #Sql = 'INSERT INTO #OutPutTable SELECT StartDate,EndDate,Amount, AccountId FROM table1';
EXEC sp_executesql #Sql, N'#OutPutTable mytabletype OUTPUT', #OutPutTable OUTPUT;
SELECT * FROM #OutPutTable
END
The above is saying I cannot pass in OUTPUT with #OutPutTable
Help!!!
all i need to know is, is there a way I can get the values from a statement executed via EXEC and return it from my SP
Yes. But you can't do it with a table variable. You can pass a table variable into the nested batch with sp_executesql just like you pass one to a stored procedure, but it has to be marked readonly, and so you can't modify it.
You can see and modify existing temporary tables in nested batches, eg
drop table if exists table1
go
create table table1
(
StartDate DATETIME,
EndDate DATETIME,
Amount MONEY,
AccountId INT
)
insert into table1 values (getdate(),getdate(),1,1)
go
CREATE OR ALTER PROCEDURE EvalClearingNetSpend
AS
BEGIN
create table #t(
StartDate DATETIME,
EndDate DATETIME,
Amount MONEY,
AccountId INT)
Declare #Sql as NVARCHAR(MAX);
SET #Sql = 'INSERT INTO #T SELECT StartDate,EndDate,Amount, AccountId FROM table1';
EXEC sp_executesql #Sql
SELECT * FROM #T
END
go
exec EvalClearingNetSpend
outputs
StartDate EndDate Amount AccountId
----------------------- ----------------------- --------------------- -----------
2021-03-30 08:48:32.350 2021-03-30 08:48:32.350 1.00 1
This is an XY Problem. There is no need for the level of complexity you have put in the procedure. The table TYPE, the call to sys.sp_executesql, none of it is needed. Just put the SELECT statement of your "dynamic" query (it's not dynamic, as there's no object injection) in your Procedure:
CREATE PROCEDURE attributevalues.EvalClearingNetSpend AS --Removed sp_ prefix
BEGIN
SELECT StartDate,EndDate,Amount, AccountId FROM table1;
END;
GO
This completely avoids the error, that you are trying to use a table TYPE as an OUTPUT parameter, because you can't, but you don't need one here.
Not sure why you would go through the trouble of creating a Table Type parameter and populating it inside your from and then selecting from it. But lets say you do have to do this for some reason.
You can achieve this by doing this, no need to use output parameters at all, output parameter is used to return a scalar value, here you are getting a table back and then selecting from it:
CREATE PROCEDURE usp_EvalClearingNetSpend
AS
BEGIN
Declare #Sql as NVARCHAR(MAX);
SET #Sql = N' DECLARE #OutPutTable AS mytabletype;
INSERT INTO #OutPutTable
SELECT StartDate,EndDate,Amount, AccountId
FROM table1;
SELECT * FROM #OutPutTable
';
EXEC sp_executesql #Sql
END

Use table columns in Exec stored procedure command SQL Server

I have a command:
exec [Database].[dbo].DepartmentChangeLevel , Department, Date, Level;
I currently specify the values manually and explicitly like this:
exec [Database].[dbo].DepartmentChangeLevel , 'Catering', '20180101 08:01:00', 3;
However, I want to run the same command and use values from a table - like this:
exec [Database].[dbo].DepartmentChangeLevel
select
[Department], [Date], [Level]
from
[Database].[dbo].[DepartmentChange]
The error message I get is
Expects parameter #department which is not supplied
Please help
You can use a Cursor instead:
Create a Cursor on your table and pass all three columns into three variables
and execute proc in the cursor.
Example :
declare db_cursor cursor
for select
[Department], [Date], [Level]
from
[Database].[dbo].[DepartmentChange];
declare #department int --your column data type
,#date datetime --your column data type
,#level varchar(10) --your column data type
OPEN db_cursor;
FETCH NEXT FROM db_cursor INTO #department, #date, #level;
WHILE ##FETCH_STATUS = 0
BEGIN
exec [Database].[dbo].DepartmentChangeLevel #department, #date, #level;
DELETE FROM [Database].[dbo].DepartmentChangeLevel ---or you can store values from DepartmentChangeLevel table into temporary table then delete those values from temporary table
WHERE [Department]=#department
and [Date]=#date
and [Level]=#level
FETCH NEXT FROM db_cursor INTO #department,#date, #level
END
CLOSE db_cursor;
DEALLOCATE db_cursor;

How to pass a table variable from one stored procedure to another

My scenario is like this,
CREATE PROCEDURE SP_1
AS
BEGIN
INSERT INTO #tmpTable(ID, Value)
VALUES(1, 1), (2, 2)
END
GO
CREATE PROCEDURE SP_2
AS
BEGIN
CREATE TABLE #tmpTable(ID INT, Value INT)
EXEC SP_1
SELECT * FROM #tmpTable
DROP TABLE #tmpTable
END
GO
EXEC SP_2
GO
DROP PROCEDURE SP_1
DROP PROCEDURE SP_2
I want to replace this # table with a TABLE VARIABLE (# Table).
I tried to passed table variable as parameter to SP_1 but I should pass table variable as read only parameter. Since it's read only I can't insert into the table variable inside SP_1. Is there any other way I can accomplish this?
It's not gonna work this way. you should encapsulate your query within a string. once done you can change the table names as you like. and then, execute using EXEC sp_executesql.
i've previously answered a similar question which can be found below:
SQL: How to make table name in stored procedure dynamic
here's the example i've provided
declare #sql nvarchar(max)
declare #TableName nvarchar(max)
set #TableName = 'mytable'
set #sql = 'Select * from ' + #TableName
Exec sp_executesql #sql
This worked for me(Sql server 2012), although I did not completely understand what you are trying to achieve:
CREATE PROCEDURE SP_1
AS
BEGIN
Create table #tmpTable (ID INT, Value INT)
INSERT INTO #tmpTable(ID, Value)
VALUES(1, 1), (2, 2)
Select ID,Value from #tmpTable
END
GO
CREATE PROCEDURE SP_2
AS
BEGIN
Declare #tmpTable table (ID INT, Value INT)
Insert into #tmpTable
EXEC SP_1
SELECT * FROM #tmpTable
END
GO
EXEC SP_2
GO
DROP PROCEDURE SP_1
DROP PROCEDURE SP_2
I prefer passing data around as [xml]. It's easier to work with for me. You could build your record set similar to the code below and pass [xml] parameters between your procedures, then parse it out as shown.
declare #record_list [xml] = (select *
from [sys].[objects]
for xml path(N'record'), root(N'record_list'));
select #record_list;
select t.c.value(N'(./schema_id/text())[1]', N'[sysname]') as [schema_id]
, t.c.value(N'(./name/text())[1]', N'[sysname]') as [name]
, t.c.value(N'(./object_id/text())[1]', N'[sysname]') as [object_id]
from #record_list.nodes(N'/record_list/record') as t(c);

stored procedure an insert exec statement cannot be nested

I have the following stored procedure which calls another stored procedure dbo.[spGetResult]
;WITH CTE
AS
(
SELECT 0 AS [Level],PNLId , PNLParentId, PNLName
FROM [dbo].[DimPNL]
WHERE PNLParentId IS NULL
UNION ALL
SELECT CTE.[Level] + 1 ,T1.PNLId,T1.PNLParentId,T1.PNLName
FROM [dbo].[DimPNL] AS T1
INNER JOIN CTE
ON T1.PNLParentId = CTE.PNLId
)
-- order the results into a #temp table
SELECT *
INTO ##temp
FROM CTE
ORDER BY level desc
DECLARE #PNLName As varchar(MAX)
DECLARE db_cursor CURSOR FOR
SELECT PNLName
FROM ##temp
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #PNLName
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO dbo.[test1]//from here I have a problem
Exec dbo.[spGetResult] #PNLName
FETCH NEXT FROM db_cursor INTO #PNLName
END
CLOSE db_cursor
DEALLOCATE db_cursor
I always get
stored procedure an insert exec statement cannot be nested
I have a look here But I didn't understand very much how to resolve the problem ?
Your best bet is to rewrite the stored procedure to a table function. Performance-wise an inline function works best, but it's usually more difficult to functionally rewrite a procedure like this.
Most stored procs can easily be rewritten to a table valued function though.
Take a look here for more info: http://technet.microsoft.com/en-us/library/ms187650(v=sql.105).aspx
Once you've rewritten it, you can nest the insert into/select statements.
INSERT INTO [TABLE] (col1, col2, ...) SELECT tvfcol1, tvfcol2, ...
from dbo.func_TVF_blabla(#param1, #param2, ...)

How to select Table and Column Names from passed parameters in SQL Server?

I have two very similar tables in our database, and I need to write a stored procedure for my Visual Studio 2010 Web Application to read the data from one of these tables given a table number.
Currently, we only have two tables to select from, but I can see this growing to more as this project grows.
This is sort of what I am trying to do, but this code is not correct:
PROCEDURE [dbo].[spGetData]
#tableID int
AS
BEGIN
SET NOCOUNT ON;
declare #col1 nvarchar(50), #table nvarchar(50)
set #col1=case when #tableID=1 then 'SMRequestID' else 'WHRequestID' end
set #table=case when #tableID=1 then 'SMRequest' else 'WHRequest' end
select #col1 as 'Request', WorkOrder, PartNumber, Qty, EmployeeID
from #table
END
Basically, the ColumnName and TableName depend on the #tableID parameter that will be passed in.
How would I go about doing that?
Note: My searches are not turning up anything related, but I am a C# developer and not a database developer. I imagine this has been asked before, it is just I am not using the right keywords.
Although I think Mark is quite correct given the small number of tables and simplicity of your queries, here is a dynamic sql example that passes both the table and column names:
CREATE PROCEDURE spGetData
(
#TableName nvarchar(128),
#ColumnName nvarchar(128)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL nvarchar(4000)
SET #SQL = 'SELECT ' + #ColumnName + ', as Request, WorkOrder, PartNumber, Qty, EmployeeID FROM ' + #TableName
EXEC sp_executesql #SQL
END
You can call it as follows:
exec spGetData 'SMRequest', 'SMRequestID'
exec spGetData 'WHRequest', 'WHRequestID'
One option would be to use a conditional based upon the ID and put the code for a specific table in each section for the table.
I prefer this method to get away from the dynamic sql and allow the database server to get a fighting chance to optimize the thing for speed reasons by precompiling.
NOTE: database servers are pretty bad at string manipulation (create dynamic sql) in general.
EDIT1: EXAMPLE
FOR INSTANCE: THIS SQL
declare #mytest varchar(5)
set #mytest = 'PROCS'
IF #mytest = 'PROCS'
BEGIN /* STORED PROCS */
SELECT DISTINCT
o.name AS ObjectName_StoredProcedure
FROM sysobjects as o
WHERE o.xtype = 'P'
END
ELSE
IF #mytest = 'DEFAULT'
BEGIN
SELECT DISTINCT
o.name AS ObjectName_StoredProcedure
FROM sysobjects as o
WHERE o.xtype = 'D'
END
gives you the store procedure names or the default constraints depending on what you pass to the parameter.
EDIT2: Based on OP code:
CREATE PROCEDURE [dbo].[spGetData]
(#tableID int )
AS
BEGIN
SET NOCOUNT ON;
IF #tableID = 1
BEGIN
SELECT SMSRequestId AS 'Request',
WorkOrder, PartNumber, Qty, EmployeeID
FROM SMRequest
END
IF #tableID = 2
BEGIN
SELECT WHRequestID AS 'Request',
WorkOrder, PartNumber, Qty, EmployeeID
FROM WHRequest
END
END
Do it with dynamic SQL:
PROCEDURE [dbo].[spGetData]
#tableID int
AS
BEGIN
SET NOCOUNT ON;
declare #col1 nvarchar(50), #table nvarchar(50), #cmd nvarchar(400)
set #col1=case when #tableID=1 then 'SMRequestID' else 'WHRequestID' end
set #table=case when #tableID=1 then 'SMRequest' else 'WHRequest' end
#cmd = "select " + #col1 + " as 'Request', WorkOrder, PartNumber, Qty, EmployeeID from " + #table
EXEC(#cmd)
END