Stored proc in Execute SQL Task not persisting changes to database - sql

I have an Execute SQL Task using an Update statement that I would like to change to a stored procedure.
My stored procedure works fine in SSMS, however when I try and use the stored proc in the Execute SQL Task, the component doesn't fail, however it doesn't persist the Updated changes to the Database.
The Connection managers are solid as the Update statement works and it wouldn't even be able to call the stored proc if the Connection manager was wrong anyway.
I have tried deleting and recreating the component but that did not help. It almost seems like the query is being executed, succeeds, and then the changes are rolled back.

I would start by checking the pstream variable type.
Your stored proc expects an INT and you are passing a NUMERIC.
I am guessing that the parcing doesn't work as expected.
Try to have your SSIS variable 'USER::Pstream' as Int32 and the Sql task parameter type as LONG
i have tried the following and works for me.
CREATE TABLE dbo.TestTable(
[BucketName] NVARCHAR(250),
[DBName] NVARCHAR(250),
[Pstream] INT
)
GO
CREATE PROCEDURE dbo.UpdateBucket
#BucketName NVARCHAR(250),
#DbName NVARCHAR(250),
#PStream INT
AS
BEGIN
UPDATE dbo.TestTable
SET BucketName = #BucketName
where DBName = #DbName and Pstream = #PStream
END
GO
INSERT INTO dbo.TestTable VALUES ('A bucket', 'A database', 100)

Add a breakpoint before the task executes so that you can inspect the variables before it executes. Once your package stops at the breakpoint, use the Watch window to see what the current values are that will be used in your stored proc. I suspect that you will find they are different than expected. If you have never used Watch, this should get you going:
Watch variables during SSIS Debug

Related

Stored procedure with temporary tables, Entity Framework updating the stored procedure not working - SET FMTONLY OFF

I have a stored procedure which has multiple temporary tables, when I tried importing it in Entity Framework it didn't create the complex type and I get this error:
The selected stored procedure or function returns no columns
When I googled, I found adding this piece of code SET FMTONLY OFF in the stored procedure will create the complex type in my EDMX. I was able to do it.
Everything works well in Entity Framework now after adding SET FMTONLY OFF.
Now my question is, is there a security threat by adding this piece of code to my stored procedure which contains multiple temp tables ?
Thank you.
You don't want to just SET FMTONLY OFF, as that could have unintended consequences, but you could return an empty result set of the right shape, then turn FMTONLY OFF and RETURN at the beginning of your stored procedure.
eg
if 1=0 --this will only run in FMTONLY is ON
begin
select cast(1 as decimal(12,0) a, cast('x' as nvarchar(20)) b -- . . .
set fmtonly off
return;
end
Since FMTONLY ignores control flow statements it will run the code in the begin/end. The client will get an empty resultset, then the procedure exists. You have to turn off FMTONLY or else the return will not be executed, and you will get an error with your temp tables later.
When this stored procedure is run without FMTONLY the if 1=0 will be evaluated, and that block skipped.
However switching out the stored procedure for one without temp tables when you update the EF model is a valid alternative.

Stored procedure with multiple 'INSERT INTO Table_Variable EXECUTE stored_procedure' statements [duplicate]

I have three stored procedures Sp1, Sp2 and Sp3.
The first one (Sp1) will execute the second one (Sp2) and save returned data into #tempTB1 and the second one will execute the third one (Sp3) and save data into #tempTB2.
If I execute the Sp2 it will work and it will return me all my data from the Sp3, but the problem is in the Sp1, when I execute it it will display this error:
INSERT EXEC statement cannot be nested
I tried to change the place of execute Sp2 and it display me another error:
Cannot use the ROLLBACK statement
within an INSERT-EXEC statement.
This is a common issue when attempting to 'bubble' up data from a chain of stored procedures. A restriction in SQL Server is you can only have one INSERT-EXEC active at a time. I recommend looking at How to Share Data Between Stored Procedures which is a very thorough article on patterns to work around this type of problem.
For example a work around could be to turn Sp3 into a Table-valued function.
This is the only "simple" way to do this in SQL Server without some giant convoluted created function or executed sql string call, both of which are terrible solutions:
create a temp table
openrowset your stored procedure data into it
EXAMPLE:
INSERT INTO #YOUR_TEMP_TABLE
SELECT * FROM OPENROWSET ('SQLOLEDB','Server=(local);TRUSTED_CONNECTION=YES;','set fmtonly off EXEC [ServerName].dbo.[StoredProcedureName] 1,2,3')
Note: You MUST use 'set fmtonly off', AND you CANNOT add dynamic sql to this either inside the openrowset call, either for the string containing your stored procedure parameters or for the table name. Thats why you have to use a temp table rather than table variables, which would have been better, as it out performs temp table in most cases.
OK, encouraged by jimhark here is an example of the old single hash table approach: -
CREATE PROCEDURE SP3 as
BEGIN
SELECT 1, 'Data1'
UNION ALL
SELECT 2, 'Data2'
END
go
CREATE PROCEDURE SP2 as
BEGIN
if exists (select * from tempdb.dbo.sysobjects o where o.xtype in ('U') and o.id = object_id(N'tempdb..#tmp1'))
INSERT INTO #tmp1
EXEC SP3
else
EXEC SP3
END
go
CREATE PROCEDURE SP1 as
BEGIN
EXEC SP2
END
GO
/*
--I want some data back from SP3
-- Just run the SP1
EXEC SP1
*/
/*
--I want some data back from SP3 into a table to do something useful
--Try run this - get an error - can't nest Execs
if exists (select * from tempdb.dbo.sysobjects o where o.xtype in ('U') and o.id = object_id(N'tempdb..#tmp1'))
DROP TABLE #tmp1
CREATE TABLE #tmp1 (ID INT, Data VARCHAR(20))
INSERT INTO #tmp1
EXEC SP1
*/
/*
--I want some data back from SP3 into a table to do something useful
--However, if we run this single hash temp table it is in scope anyway so
--no need for the exec insert
if exists (select * from tempdb.dbo.sysobjects o where o.xtype in ('U') and o.id = object_id(N'tempdb..#tmp1'))
DROP TABLE #tmp1
CREATE TABLE #tmp1 (ID INT, Data VARCHAR(20))
EXEC SP1
SELECT * FROM #tmp1
*/
My work around for this problem has always been to use the principle that single hash temp tables are in scope to any called procs. So, I have an option switch in the proc parameters (default set to off). If this is switched on, the called proc will insert the results into the temp table created in the calling proc. I think in the past I have taken it a step further and put some code in the called proc to check if the single hash table exists in scope, if it does then insert the code, otherwise return the result set. Seems to work well - best way of passing large data sets between procs.
This trick works for me.
You don't have this problem on remote server, because on remote server, the last insert command waits for the result of previous command to execute. It's not the case on same server.
Profit that situation for a workaround.
If you have the right permission to create a Linked Server, do it.
Create the same server as linked server.
in SSMS, log into your server
go to "Server Object
Right Click on "Linked Servers", then "New Linked Server"
on the dialog, give any name of your linked server : eg: THISSERVER
server type is "Other data source"
Provider : Microsoft OLE DB Provider for SQL server
Data source: your IP, it can be also just a dot (.), because it's localhost
Go to the tab "Security" and choose the 3rd one "Be made using the login's current security context"
You can edit the server options (3rd tab) if you want
Press OK, your linked server is created
now your Sql command in the SP1 is
insert into #myTempTable
exec THISSERVER.MY_DATABASE_NAME.MY_SCHEMA.SP2
Believe me, it works even you have dynamic insert in SP2
I found a work around is to convert one of the prods into a table valued function. I realize that is not always possible, and introduces its own limitations. However, I have been able to always find at least one of the procedures a good candidate for this. I like this solution, because it doesn't introduce any "hacks" to the solution.
I encountered this issue when trying to import the results of a Stored Proc into a temp table, and that Stored Proc inserted into a temp table as part of its own operation. The issue being that SQL Server does not allow the same process to write to two different temp tables at the same time.
The accepted OPENROWSET answer works fine, but I needed to avoid using any Dynamic SQL or an external OLE provider in my process, so I went a different route.
One easy workaround I found was to change the temporary table in my stored procedure to a table variable. It works exactly the same as it did with a temp table, but no longer conflicts with my other temp table insert.
Just to head off the comment I know that a few of you are about to write, warning me off Table Variables as performance killers... All I can say to you is that in 2020 it pays dividends not to be afraid of Table Variables. If this was 2008 and my Database was hosted on a server with 16GB RAM and running off 5400RPM HDDs, I might agree with you. But it's 2020 and I have an SSD array as my primary storage and hundreds of gigs of RAM. I could load my entire company's database to a table variable and still have plenty of RAM to spare.
Table Variables are back on the menu!
I recommend to read this entire article. Below is the most relevant section of that article that addresses your question:
Rollback and Error Handling is Difficult
In my articles on Error and Transaction Handling in SQL Server, I suggest that you should always have an error handler like
BEGIN CATCH
IF ##trancount > 0 ROLLBACK TRANSACTION
EXEC error_handler_sp
RETURN 55555
END CATCH
The idea is that even if you do not start a transaction in the procedure, you should always include a ROLLBACK, because if you were not able to fulfil your contract, the transaction is not valid.
Unfortunately, this does not work well with INSERT-EXEC. If the called procedure executes a ROLLBACK statement, this happens:
Msg 3915, Level 16, State 0, Procedure SalesByStore, Line 9 Cannot use the ROLLBACK statement within an INSERT-EXEC statement.
The execution of the stored procedure is aborted. If there is no CATCH handler anywhere, the entire batch is aborted, and the transaction is rolled back. If the INSERT-EXEC is inside TRY-CATCH, that CATCH handler will fire, but the transaction is doomed, that is, you must roll it back. The net effect is that the rollback is achieved as requested, but the original error message that triggered the rollback is lost. That may seem like a small thing, but it makes troubleshooting much more difficult, because when you see this error, all you know is that something went wrong, but you don't know what.
I had the same issue and concern over duplicate code in two or more sprocs. I ended up adding an additional attribute for "mode". This allowed common code to exist inside one sproc and the mode directed flow and result set of the sproc.
what about just store the output to the static table ? Like
-- SubProcedure: subProcedureName
---------------------------------
-- Save the value
DELETE lastValue_subProcedureName
INSERT INTO lastValue_subProcedureName (Value)
SELECT #Value
-- Return the value
SELECT #Value
-- Procedure
--------------------------------------------
-- get last value of subProcedureName
SELECT Value FROM lastValue_subProcedureName
its not ideal, but its so simple and you don't need to rewrite everything.
UPDATE:
the previous solution does not work well with parallel queries (async and multiuser accessing) therefore now Iam using temp tables
-- A local temporary table created in a stored procedure is dropped automatically when the stored procedure is finished.
-- The table can be referenced by any nested stored procedures executed by the stored procedure that created the table.
-- The table cannot be referenced by the process that called the stored procedure that created the table.
IF OBJECT_ID('tempdb..#lastValue_spGetData') IS NULL
CREATE TABLE #lastValue_spGetData (Value INT)
-- trigger stored procedure with special silent parameter
EXEC dbo.spGetData 1 --silent mode parameter
nested spGetData stored procedure content
-- Save the output if temporary table exists.
IF OBJECT_ID('tempdb..#lastValue_spGetData') IS NOT NULL
BEGIN
DELETE #lastValue_spGetData
INSERT INTO #lastValue_spGetData(Value)
SELECT Col1 FROM dbo.Table1
END
-- stored procedure return
IF #silentMode = 0
SELECT Col1 FROM dbo.Table1
Declare an output cursor variable to the inner sp :
#c CURSOR VARYING OUTPUT
Then declare a cursor c to the select you want to return.
Then open the cursor.
Then set the reference:
DECLARE c CURSOR LOCAL FAST_FORWARD READ_ONLY FOR
SELECT ...
OPEN c
SET #c = c
DO NOT close or reallocate.
Now call the inner sp from the outer one supplying a cursor parameter like:
exec sp_abc a,b,c,, #cOUT OUTPUT
Once the inner sp executes, your #cOUT is ready to fetch. Loop and then close and deallocate.
If you are able to use other associated technologies such as C#, I suggest using the built in SQL command with Transaction parameter.
var sqlCommand = new SqlCommand(commandText, null, transaction);
I've created a simple Console App that demonstrates this ability which can be found here:
https://github.com/hecked12/SQL-Transaction-Using-C-Sharp
In short, C# allows you to overcome this limitation where you can inspect the output of each stored procedure and use that output however you like, for example you can feed it to another stored procedure. If the output is ok, you can commit the transaction, otherwise, you can revert the changes using rollback.
On SQL Server 2008 R2, I had a mismatch in table columns that caused the Rollback error. It went away when I fixed my sqlcmd table variable populated by the insert-exec statement to match that returned by the stored proc. It was missing org_code. In a windows cmd file, it loads result of stored procedure and selects it.
set SQLTXT= declare #resets as table (org_id nvarchar(9), org_code char(4), ^
tin(char9), old_strt_dt char(10), strt_dt char(10)); ^
insert #resets exec rsp_reset; ^
select * from #resets;
sqlcmd -U user -P pass -d database -S server -Q "%SQLTXT%" -o "OrgReport.txt"

Stored Procedure gives Cannot find object... error in SSIS, but works fine in SSMS

I am trying to build an SSIS package that dynamically rebuilds the indexes for all the tables in my database. The general idea is that the package will make sure that the table is not being update and then execute a stored procedure that drops the old index, if it exists, and then recreates it. The logic behind the package seems to be sound. The problem that I am having is when I execute the package I keep getting the error:
Cannot find object...because it does not exist or you do not have permission...
The index existing should be irrelevant due to the IF EXISTS part.
The procedure looks like this:
REFERENCE_NAME AS VARCHAR(50),
COLUMN_NAME AS VARCHAR(50),
INDEX_NAME AS VARCHAR(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX)
SET #sql = 'IF EXISTS (SELECT name FROM sysindexes WHERE name = '+CHAR(39)+#INDEX_NAME+CHAR(39)+') '+
'DROP INDEX '+#INDEX_NAME+' ON '+#REFERENCE_NAME+' '+
'CREATE INDEX '+#INDEX_NAME+' ON '+#REFERENCE_NAME+'('+#COLUMN_NAME+') ON [INDEX]'
EXEC sp_executesql #sql
END
GO
I am able to execute the procedure through SSMS just fine, no error and it builds the index. When I execute the package in SSIS it errors out the minute it gets to the task that executes the stored procedure. I have made sure that SSIS is passing the variables to the execute SQL task and I have verified that I have db_ddladmin rights. Outside of that I am at a loss and have been beating my head against the wall for a day and a half on this.
Is there something I am missing, some permissions I need to request, or some work around for the issue?
Any information would be much appreciated.
Bartover, its definitely not looking at the wrong database. I have checked that the proc is there and the only connection on the package is to that specific database. Yes, I am executing the package manually with Visual Studios 2010 Shell Data Tools.
Sorrel, I tried your idea of a sanity check on the #sql statement on the drop, on both the drop and create, and on whole #sql statement, no joy.
Gnackenson, I had that same thought, but the connection authentication method is set to Windows Authentication, same as ssms. Do you have any ideas as to why it might use different permissions?
It looks like IF EXISTS is being ignored by SSIS SQL Task. To fix my problem, I altered my SQL tasks from DROP - CREATE to DISABLE - ENABLE.

SQL Server 2012 stored procedure output being interrupted by contained procedure's result set

long time reader, first time poster.
We're observing something strange in our production instance of SQL Server 2012 after we migrated our application's databases from dev, to test, to production for our recent go-live.
We have a number of stored procedures are called from a WCF web service to do various operations; some return result sets, others do not.
Some of these procedures call other (sub) procedures within them. These sub procedures have defined OUTPUT parameters. When the parent procedures are called in dev and test, they execute as expected and the returned result set is the final select statement.
But in our production environment, the parent procedures ARE running to completion when called, but instead of returning the expected result set like before, they return the sub procedure's OUTPUT parameter.
Below is an example excerpt from one of our procedures that demonstrates the issue:
CREATE PROCEDURE [dbo].[CHANGE_USER_DEPTID]
#USERID VARCHAR(10),
#DEPTID VARCHAR(10)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #ALTERNATEUSERID VARCHAR(10)
DECLARE #EMPLID INT
EXEC GET_ALTERNATEUSERID_SP #USERID, #ALTERNATEUSERID OUTPUT
SELECT #EMPLID = EMPLID FROM ACTIVEDIRECTORY_VW WHERE ALTID = #ALTERNATEUSERID
...DO SOME VARIOUS PROCESSING...
UPDATE DEPARTMENT_TABLE
SET EMPLID = ...
WHERE ...
END
Ok, so this procedure's final statement is an update, and in our dev and test environments, when this CHANGE_USER_DEPTID procedure is called, it simply returns "Command(s) Completed Successfully". But in our production environment, the procedure returns a result set; the #ALTERNATEUSERID which is the output parameter of the sub procedure. How is that possible? The main procedure is never even selecting that variable, and the main procedure doesn't even HAVE an output parameter defined.
This isn't a big deal on some of the calls in the WCF service, because the .NET method uses them in a cmd.ExecuteNonQuery() statement. But it IS causing problems for some others where we're expecting the final select statement to return a certain result set at the end of the procedure (an integer, for example), but instead it returns the output parameter of the sub procedure (say, a string), which is causing various things to blow up further down the line.
Has anyone ever experienced, or even heard of this issue?
To wrap this up:
It turned out that one of the child stored procedures inside the parent procedure (about three levels deep) had an extra SELECT statement at the end which someone had uncommented for testing purposes. That extra select statement was being returned all the way up the stack in the topmost stored procedure.

Can't execute stored procedure

I have created a stored procedure and can see it under the stored procedure node, but when trying to execute it doesn't find the procedure.
Under stored procedure node it is called dbo.CopyTable
exec CopyTable
CopyTable is undefined in red saying it does not exist. Why?
Even if I right-click on the procedure and say script stored procedure as execute to - the code it generates is underlined in red and cant find stored procedure either.
Ensure that the database selected contains the stored procedure CopyTable
USE YourDatabase
EXEC CopyTable
Try adding dbo and selecting the right database,
USE databaseName
GO
EXEC dbo.CopyTable
GO
Execute a Stored Procedure
Most likely you are just in the wrong database in the query window, you can specify the database like this:
EXEC [yourDBName].dbo.CopyTable
Reading on how to Execute a Stored Procedure
Considering your updated question:
Even if i rightclick on the procedure and say script stored procedure
as execute to - the code it generates is underlined in red and cant
find stored procedure either.
This could happen if your stored procedure is invalid. Please double-check the validity of the SPROC and ensure the tables it references exist, etc.
Try running your CREATE PROCEDURE. Highlight it, f5 it, and then make sure it runs before you call it elsewhere.
Maybe in your procedure you've accidentally cut-pasted your script name (dbo.CopyTable), say something like...
SELECT * FROM dbo.CopyTable
WHERE ClientId = #ClientId
RETURN
Then when you call your proc you get 'invalid object name dbo.CopyTable' and assume sql is having trouble finding the stored-proc ... which isn't the problem, its finding and running the proc but its actually a problem within the proc.