How do I combine result sets from two stored procedure calls? - sql

I have a following stored procedure
CREATE PROCEDURE [dbo].[MyStored]
#state int
AS
SELECT blahblahblah WHERE StoredState=#state LotsOfJoinsFollow;
RETURN 0
and I'd like to call that stored procedure with #state being 0 and 1 and have the result sets returned by both calls combined with UNION semantics so that I have a new resultset that has rows from both the first call and the second call.
Something like (imaginary SQL):
(EXEC MyStored 0) UNION (EXEC MyStored 1);
How do I achieve that?

This may be oversimplifying the problem, but if you have control over the sp, just use in rather than =:
CREATE PROCEDURE [dbo].[MyStored]
AS
SELECT blahblahblah WHERE StoredState IN (0,1) LotsOfJoinsFollow;
RETURN 0
If this is not an option, just push the results of both sproc calls into a temp table:
/*Create a table with the same columns that the sproc returns*/
CREATE TABLE #tempblahblah(blahblahblah NVARCHAR(50))
INSERT #tempblahblah ( blahblahblah )
EXEC MyStored 0
INSERT #tempblahblah ( blahblahblah )
EXEC MyStored 1
SELECT * FROM #tempblahblah

create table #table (
.....
)
insert into #table exec MyStored 0
insert into #table exec MyStored 1
select * from #table
drop table #table

Alternatively to a series of statements like these:
INSERT INTO #YourTempTable
EXEC MyStored 0;
INSERT INTO #YourTempTable
EXEC MyStored 1;
you could use one INSERT ... EXEC statement like below:
INSERT INTO #YourTempTable
EXEC ('
EXEC MyStored 0;
EXEC MyStored 1;
');
The results of the two calls to MyStored would be UNIONed (or, rather, UNION ALLed), just like with the former method.

A long way would be to create a wrapper that does this - a function that takes a list of states and adds them to a final table that would be returned.
You could also have whatever technology is calling this procedure do the concatination of records (i.e. having .NET append the result set of each state you are looking into)
If you're fine with passing in a list of states to your 'state' param, you could create a dynamic sql query
CREATE PROCEDURE [dbo].[MyStored]
#state nvarchar(150)
AS
-- #state needs to be pre-formatted in a list for an in-clause
-- i.e. 1,2,10 (if it was a string list, you'd need to do use double single quotes around the items - ''1'',''2'',''10''
DECLARE #SQL nVarChar(5000) = '
SELECT blahblahblah
FROM LotsOfJoins
WHERE StoredState in (' + #state + ')'
exec sp_executeSql #sql
This works great for simple procedures; although, it can get take longer to maintain if changes are needed down the road.
.
Here is a CodeProject Article and a MS SQL Tips Article that does a better job going into details
.
EDIT: The param #state will need to be a nVarChar since your passing in a comma delimited list of int values

If the stored procedure you are calling has a temp table with the same name as one in the calling procedure you will get this error.
e.g. sp1 has temp table #results
sp2 create table #results(fields)
then trying to insert into #results in sp2 the result of calling sp1 would fail with this error. change temp table in sp2 to #result and try again and you should see this now works.

Related

Inserting into a user-defined table type via a dynamic query in SQL Server?

I have a user-defined table type tyAnalysisNumbers. I need to populate my user defined data type within a stored procedure with a SELECT statement and I am struggling to get that working within my stored procedure.
The following ways I have tried do not work
DECLARE #MyTable tyAnalysisNumbers;
INSERT INTO #MyTable
EXEC ('SELECT * FROM ' + #someTable);
I get this error:
An INSERT EXEC statement cannot be nested
I am unsure how to insert into my custom table via a select statement.
Can anyone help me accomplish this?
An INSERT EXEC statement cannot be nested
Above error is self explanatory. Please look at below scenario:
For example, we have one procedure which inserts data in table type and return result.
CREATE PROCEDURE uspInsertData1
AS
BEGIN
DECLARE #MyTable tyAnalysisNumbers;
INSERT INTO #MyTable
EXEC ('SELECT * FROM someTable');
select * from #MyTable
END
Now, let's say we have another procedure which will call above procedure and again insert data in another table.
CREATE PROCEDURE uspInsertData2
AS
BEGIN
DECLARE #MyTable tyAnalysisNumbers;
INSERT INTO sometable
EXEC uspInsertData1
END
Now, if you execute 1st procedure it will work fine but if you execute second procedure you will get this error.
An INSERT EXEC statement cannot be nested.
Because now you have nested EXEC statements.
I suggest to finish your work in single stored procedure if possible.
Try it like this:
DECLARE #MyTable tyAnalysisNumbers;
SELECT * INTO #Temp FROM #MyTable;
DECLARE #tblName AS SYSNAME = (SELECT name FROM sys.tables WHERE name = #someTable);
EXEC ('INSERT INTO #Temp SELECT * FROM ' + #tblName);
This also addresses the SQL Injection problem.

How can I assign an exec result to multiple sql variables?

I got the returned data after executing a stored procedure named [s_sspCallSharePointWebService] in SSMS
DECLARE #sWebAddr AS NVARCHAR(MAX),
#bAPISuccess AS NVARCHAR(10),
#objSharePointXML AS XML
SET #sWebAddr = 'http://...'
EXEC [s_sspCallSharePointWebService] #sWebAddr, #bAPISuccess OUTPUT, #objSharePointXML OUTPUT
I was wondering how do I save
the data in variables instead of returning a table below.
---------------------------------------
| (No column name) | (No column name) |
---------------------------------------
| True | <XMLRoot>.... |
---------------------------------------
Additionally, I cannot insert the data into a temp table here because I had the result of EXEC sp_OAGetProperty #objecttoken, 'responseText' in [s_sspCallSharePointWebService], and then already inserted the response text into a temp table.
That would cause an error:
An INSERT EXEC statement cannot be nested
It is very ugly (for me), but this can be done using temporary tables. The temporary table is visible to all routines in the current scope.
So, you can have nesting like this:
EXEC SP1
...
EXEC SP2
...
EXEC SP3
...
and let's say EXEC SP2 is returning a row set executing a SELECT statement. So, the question is how to materialized it?
CREATE PROCEDURE dbo.SP1
AS
BEGIN;
SELECT 'SP1' AS [Caller];
EXEC dbo.SP2;
END;
GO
CREATE PROCEDURE dbo.SP2
AS
BEGIN;
SELECT 'SP2' AS [Caller];
INSERT INTO #TEST
SELECT 1;
END;
GO
CREATE TABLE #TEST
(
[ID] INT
);
EXEC dbo.SP1;
SELECT *
FROM #TEST;
The idea is to create the temporary table in the outer scope and the procedure to be sure that this table is already created and populate it. Then, use the table in the initial caller.
It's ugly for me, because if this table is not defined the routine will cause an error:
Msg 208, Level 16, State 0, Procedure dbo.SP2, Line 8 [Batch Start
Line 0] Invalid object name '#TEST'.
and it can be difficult to debug in some cases.
Instead of doing that, you can just use a table variable, and then SELECT from it to assign. Here's an example with a simple proc that returns a single row:
USE tempdb;
GO
CREATE OR ALTER PROC dbo.ReturnsOneRow
AS
BEGIN
SELECT 1 AS FirstColumn, 'Hello' AS SecondColumn, 4 AS ThirdColumn;
END;
GO
EXEC dbo.ReturnsOneRow;
GO
DECLARE #FirstColumn int;
DECLARE #SecondColumn varchar(20);
DECLARE #ThirdColumn int;
DECLARE #Row TABLE
(
FirstColumn int,
SecondColumn varchar(20),
ThirdColumn int
);
INSERT #Row
(
FirstColumn, SecondColumn, ThirdColumn
)
EXEC dbo.ReturnsOneRow;
SELECT TOP(1) #FirstColumn = r.FirstColumn,
#SecondColumn = r.SecondColumn,
#ThirdColumn = r.ThirdColumn
FROM #Row AS r;
-- Check the values
SELECT #FirstColumn, #SecondColumn, #ThirdColumn;
The table variable will be way better than a temp table in this situation, and you don't have issues with its visibility elsewhere, or having to clean it up (it's gone at the end of the batch).

Creating a stored procedure using variables

Is there any good way to do this, or am I just heading in the wrong direction? I would like to create a stored procedure inside an SQL script. I would like to have variables declared at the beginning of the script so that I can create the SPROCs to use in different contexts/servers.Here is what I would like to do (I know this obviously doesn't work, but I'm looking for any ideas of an alternative)..
DECLARE #golbalValue = 'SomeValue'
GO
CREATE PROCEDURE [dbo].[MyStoredProcedure](
AS
BEGIN
SELECT * FROM Mytable WHERE MyCol = #globalValue
END
GO
What you could do is use a scalar function for the variable
create function f ()
returns varchar(20)
as
begin
return 'some value'
end
go
then use it in your procedure
create proc p ()
as
begin
select *
from my_table
where col = f()
end
go
another possibility which is perhaps more appropriate is to use sqlcmd here's an example.
From what I understand, you need to create stored procedures with set value from your parameters. You don't want input parameters in the stored Procedures though. Second, you want to switch database contexts. So I think you'll need a tempTable for your parameters and some dynamic SQL. Try this out:
IF OBJECT_ID('tempdb..#globalParam') IS NOT NULL
DROP TABLE #globalParam;
IF OBJECT_ID('AdventureWorks2012.dbo.myTable') IS NOT NULL
DROP TABLE AdventureWorks2012.dbo.myTable
IF OBJECT_ID('Master..myTable') IS NOT NULL
DROP TABLE Master..mytable
--Create your data tables
SELECT 'SomeValue' AS col1 INTO AdventureWorks2012.dbo.myTable;
SELECT 1000 AS col1 INTO master.dbo.myTable;
CREATE TABLE #globalParam(
ParamName VARCHAR(100),
val SQL_VARIANT --SQL_Variant is designed to hold all data types.
);
--Here are your globalParams
DECLARE #globalParam1 VARCHAR(100) = 'SomeValue';
DECLARE #globalParam2 INT = 1000;
--Load your parameters into a table. Might have to cast some of your parameters to SQL_Variant
INSERT INTO #globalParam
VALUES ('globalParam1',#globalParam1),
('globalParam2',CAST(#globalParam2 AS sql_variant));
GO
--Switch database context
USE AdventureWorks2012
GO
--Variable to hold CREATE PROC
DECLARE #sql VARCHAR(MAX);
--Set #SQL with parameter value from #globalParam
SELECT #sql =
'CREATE PROCEDURE dbo.myStoredProc AS
BEGIN
SELECT * FROM myTable WHERE col1 = ''' + CAST(val AS VARCHAR(100)) + '''
END'
FROM #globalParam
WHERE ParamName = 'globalParam1'
--Execute to create the stored procedure
EXEC(#sql)
--Execute it to see if it works
EXEC dbo.myStoredProc
--Switch context. Repeat same steps
USE master
GO
DECLARE #sql VARCHAR(MAX);
SELECT #sql =
'CREATE PROCEDURE dbo.myStoredProc AS
BEGIN
SELECT * FROM myTable WHERE col1 = ''' + CAST(val AS VARCHAR(100)) + '''
END'
FROM #globalParam
WHERE ParamName = 'globalParam2'
EXEC(#sql)
EXEC dbo.myStoredProc
--Cleanup
DROP PROCEDURE dbo.myStoredProc;
USE AdventureWorks2012
GO
DROP PROCEDURE dbo.myStoredProc;
You cannot do what you want. T-SQL doesn't have the concept of global variables. One method is to store values in a "global" table and then reference them as needed. Something like:
create table GlobalParams (
name varchar(255) not null primary key,
value varchar(255) not null
);
create procedure . . .
begin
. . .
declare #value varchar(255);
select #value = value from Globalparams where name = 'name';
select *
from Mytable
where MyCol = #value;
. . .
end;
Note: this is a simplistic example that only allows variables whose type is a string.
You can also wrap the logic in a user-defined function, so the call looks like:
select *
from Mytable
where MyCol = udf_GlobalLookup('name');
It is rather rare to need global parameters that are shared among different stored procedures. Such a global context can be useful, at times, for complex systems. It is unlikely that you need all this machinery for a simple application. An alternative method, such as just passing the parameters in as arguments, is probably sufficient.

Execute store procedure like a "table" for SELECT operator (MS SQL SERVER)

Is it possible to execute store procedure
like a "table" for SELECT operator (MS SQL SERVER)?
Something like
SELECT TotalSum FROM exec MyStoreProcedure '2011/11/01', '2011/11/01'
I mean somehow integrate it into the SELECT operator?
Thank you!
Thanks guys!
The solution what I did is based on your answers:
declare #result table (f1 varchar(20),f2 varchar(20), CodProducto int, NomProducto varchar(1000), Costo decimal, Cantidat int, Total decimal)
INSERT INTO #result exec MyStoreProcedure '20111201', '20111201'
select * from #result
I supposed your proc returns several columns and you just want one, right?
small workaround is to add the result of the proc to a table variable and then select from it
create proc proc1 as
select 1 as one, 2 as two
declare #result table (one int, two int)
insert into #result
exec proc1
select one from #result
This would be better as a function rather than a stored procedure.
create function dbo.TestTable
(#var1 bit)
returns table
AS
RETURN
( select *
from INFORMATION_SCHEMA.TABLES
where #var1 = 1
);
select * from
dbo.TestTable(1)
Not directly (or without altering the stored procedure to be a table-valued function).
But you could do this:
INSERT INTO SomeTempTableWithSchemaMatchingTheSproc (...)
EXEC MyStoredProcedure
SELECT * FROM SomeTempTableWithSchemaMatchingTheSproc
SQL Server 2005 onwards, you can also use a table variable.
This works for me:
CREATE VIEW dbo.vw_xxx
AS
select * from openquery(YOURSERVERNAME, 'exec [sp_xxx] '''','''','''','''','''','''' ')

How to query from a stored procedure in SQL Server?

Let say I have a simple Stored Procedure:
ALTER PROCEDURE [dbo].[myProc]
AS
BEGIN
SELECT * FROM myTable
END
How can I do a WHERE statement in Microsoft SQL Server Management Studio to the stored procedure? Something like that:
SELECT * FROM myProc WHERE x = 'a'; -- But that doesn't work...
It sounds like you're trying to make a "dynamic" stored procedure.
Something you might want to do is:
1) Insert the contents of your stored procedure into a temporary table
2) Use dynamic sql to apply a where condition to that temporary table.
Something like:
declare #as_condition varchar(500); --Your condition
create table #a
(
id bigint
)
insert into #a
execute sproc
declare #ls_sql varchar(max);
set #ls_sql = "select * from #a where " + #as_condition;
execute (#ls_sql);
SQL Server allows you to use INSERT INTO to grab a stored procedure's output. For example, to grab all processes with SPID < 10, use:
create table #sp_who (
spid smallint,
ecid smallint,
status nchar(30),
loginame nchar(128),
hostname nchar(128),
blk char(5),
dbname nchar(128),
cmd nchar(16),
request int)
insert into #sp_who execute sp_who
select * from #sp_who where spid < 10
You can't add a WHERE clause to a stored procedure like this.
You should put the clause in the sproc, like this:
ALTER PROCEDURE [dbo].[myProc]
#X VARCHAR(10)
AS
BEGIN
SELECT * FROM myTable WHERE x=#X
END
GO
The syntax for calling a stored procedure is through the use of EXECUTE not SELECT(e.g.):
EXECUTE dbo.myProc 'a'
I think you can't do that.
The command to execute a stored procedure is EXECUTE.
See some more examples of the EXECUTE usage.
I think its better to use a view or a table valued function rather than the suggested approach. Both allow you to pass parameters to the function
If you want the WHERE clause to be something you can "turn off" you can do this, passing in a predetermined value (e.g. -1) if the WHERE limitation is to be bypassed:
ALTER PROCEDURE [dbo].[myProc]
#X VARCHAR(10)
AS
BEGIN
SELECT * FROM myTable WHERE x=#X or #X = -1
END
GO
You must declare a variable in the store procedure which will be necessary to pass to run the stored procedure. Here is an example. Keep this in mind: Before AS you can simply declare any variable by using the # character, but after the AS you must write Declare to declare any variable, e.g., Declare #name nvarchar (50).
ALTER PROCEDURE [dbo].[myProc]
#name varchar (50)
AS
BEGIN
SELECT * FROM myTable
where name= #name
END