SSIS has validation error on SQL Server stored procedure - sql-server

I'm trying to call a custom stored procedure in SQL Server 2008 R2 from SSIS in Visual Studio 2012. I wrote and tested the stored procedure in SSMS 2012 and it works as expected.
However, when I try to place it in an OLE DB Command component I receive a Divide by 0 error when I refresh the component or when the SSIS package validates.
Here's the code for the stored procedure:
CREATE PROCEDURE [ldg].[2015HRUpdate(TEST)]
#Employee varchar(20), -- maps to EM.Employee, primary key
#Title varchar(50), -- maps to EM.Title
#PayRate varchar(50) = '0', -- maps to EM.JobCostRate, convert to decimal
-- #Percentage Decimal(19,4) = 0, -- workaround
#OldPayRate Decimal(19,4) = 0, -- used to calculate Employees_SalaryHistory.Custnprcent, convert to decimal
#LaborCategory varchar(50) = '0', -- maps to EM.BillingCategory, convert to small int
#EmployeeDesignation varchar(50), -- maps to EmployeeCustomTabFields.CustEmployeeDesg
#FSLAStatus varchar(50), -- maps to EmployeeCustomTabFields.CustFSLAStatus
#Supervisor varchar(20), -- maps to EM.Supervisor
#SupervisorName varchar(255), -- maps to Employees_SalaryHistory.custSuper
#ModUser nvarchar(20),
#ModDate datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Convert data types to match database data types
declare #JobCostRate decimal(19,4);
declare #OldJobCostRate decimal(19,4);
declare #BillingCategory smallint;
declare #Percent decimal(19,4);
if #PayRate is null or #PayRate = ''
set #PayRate = '0';
set #JobCostRate = CONVERT(decimal(19,4), #PayRate);
set #OldJobCostRate = #OldPayRate;
/* this works in T-SQL but when SSIS tries to validate I get a div/0 error */
if #OldJobCostRate != 0
begin
set #Percent = ((#JobCostRate - #OldJobCostRate)/#OldJobCostRate) * 100; --errors out right here with a divide by 0 error.
--set #Percent = 0;
end
else
begin
set #Percent = 0;
end
set #BillingCategory = CONVERT(smallint, #LaborCategory);
-- SQL statements for procedure here
-- Update EM table
-- Update EmployeeCustomTabFields table
-- Insert into Salary history table
END
GO
I have placed a comment on the line that produces the error. If I comment that line out and uncomment the one below it SSIS will validate the procedure without issue.
I finally worked around the issue by creating a derived field in the ETL but I would like to know why SSIS/OLE-DB is causing this issue for the next time it pops up.
Thanks,
Roy

If you alter your procedure to look like
SET NOCOUNT ON;
-- This is a bloody hack to get SSIS to be happy about metadata.
IF 1=2
BEGIN
SELECT 1 AS StupidHackery;
END
I believe you'll get around this issue. The root cause is that SSIS wants to validate the metadata from the proc and doesn't actually evaluate the logic in there. I don't have any definitive resources on the matter, pity, but for me at least, I could recreate your issue and by using this stupid hack, get around it. I've had to use the same thing when dealing with temporary tables.

Related

Silent exception shown in SQL Server Profiler

The following SQL script produces an Invalid object name '#temp' exception on SQL Server Profile, but neither SQL Server Management Studio nor sqlcmd raise the exception:
create table #temp (id int)
insert into #temp (id) values (1)
I only caught it by running SQL Server Profiler with the event "Exception" turned on, which can be set on the "Events Selection" tab when configuring the trace properties.
Since exceptions tend to slow down the server, I tried a similar code using a table variable:
declare #temp table (id int)
insert into #temp (id) values (1)
The code above not only avoid the exception, but is also faster when calling it repeatedly, which comproves the performance penalty by using a temporary table:
if (db_id('performance_test') is null)
create database performance_test
go
use performance_test
go
/* --------------------------- */
/* stress test with temp table */
/* --------------------------- */
declare
#i int,
#sql varchar(max),
#start_time datetime,
#end_time datetime
set #i = 0
set #sql = 'create table #temp (id int)' + Char(13) + Char(10) + 'insert into #temp (id) values (1)'
set #start_time = getdate()
while (#i < 10000)
begin
exec (#sql)
set #i = #i + 1
end
set #end_time = getdate()
select [Elapsed milliseconds] = datediff(millisecond, #start_time, #end_time) -- outputs 17090 milliseconds
go
/* ------------------------------- */
/* stress test with table variable */
/* ------------------------------- */
declare
#i int,
#sql varchar(max),
#start_time datetime,
#end_time datetime
set #i = 0
set #sql = 'declare #temp table (id int)' + char(13) + char(10) + 'insert into #temp (id) values (1)'
set #start_time = getdate()
while (#i < 10000)
begin
exec (#sql)
set #i = #i + 1
end
set #end_time = getdate()
select [Elapsed milliseconds] = datediff(millisecond, #start_time, #end_time) -- outputs 10010 milliseconds
I often read that a local temporary table and a table variable can be used interchangeably (if using a single batch, of course), however I think the demonstrated behavior above can prove otherwise.
Although it's kinda obvious, it's worth noting that the exception is not raised if we separate the create table from insert into in different batches:
create table #temp (id int)
go
insert into #temp (id) values (1)
Is this silent exception a SQL Server's bug or is it something that could be called "a feature by design"? Maybe it's simply better to always use table variables instead of temporary tables, given the silent exception above.
P.S.: I've tested on both SQL Server 2014 and SQL Server 2016 Developer editions, getting the same results.
As pointed out by #JeroenMostert, the exception "Invalid object name" is probably resolved in the batch recompilation (which I didn't know about). It makes perfect sense considering the "Deferred name Resolution" process, which is a known subject in the SQL Server community.
The first link below is a question I've posted on MSDN and was answered by Mohsin_A_Khan, talking about "Deferred name Resolution" process in SQL Server. The other two links contributes to understand how it actually works:
Getting "Invalid object name" by creating a temp table and inserting rows right away
How to find what caused errors reported in a SQL Server profiler trace?
Deferred Name Resolution and Compilation
Since the "Invalid object name" is expected due to the recompilation process and shouldn't be avoided by simply replacing the temporary table with a table variable (again, as pointed out by #JeroenMostert), I consider this question answered.

How to Update or Insert a record using SQL Merge

I have a windows forms application that needs to edit an existing record if it already exists and create it if it does not. I'm using SQL Server 2008 R2. My application reads data from various tables which includes an ID field for the output table if a record already exists.
The ID field is blank if a new record is being created. The ID field is the primary key and an Identity (auto increment) field for the destination table.
I have created a stored procedure using MERGE that I hope will create a new record or update the existing one. The update part is working but I can't figure out what to do with the ID field when creating.
When doing an update I pass in an ID Parameter and the existing record is located. Obviously if it is a new record I won't have an ID yet but I can't then leave that Parameter out or I get an unassigned variable error as you would expect.
Here is my stored procedure. Am I just barking up the wrong tree here
somewhere?
Should I just create two stored procedures and call Update if I have and ID and Call Create if I don't have and ID?
Thanks for any assistance.
USE [Insurance]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[CreateModifyValuation]
-- Add the parameters for the stored procedure here
#ValuationID int,
#OwnersCorporationID int,
#ValDate datetime,
#ValuerID int,
#Amount money,
#Printed bit,
#Approved bit,
#Notes varchar(max),
#MultiplierValue money,
#MultiplierClass char(10),
#Adjustment money,
#SubmittedDate datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
Merge Valuation as Target
USING (Select
#ValuationID,
#OwnersCorporationID,
#ValDate,
#ValuerID,
#Amount,
#Printed,
#Approved,
#Notes,
#MultiplierValue,
#MultiplierClass,
#Adjustment,
#SubmittedDate
)
As Source(
ValuationID,
OwnersCorporationID,
ValDate,
ValuerID,
Amount,
Printed,
Approved,
Notes,
MultiplierValue,
MultiplierClass,
Adjustment,
SubmittedDate
)
ON Source.ValuationID = Target.ValuationID
WHEN MATCHED THEN
UPDATE SET
Target.OwnersCorporationID = Source.OwnersCorporationID,
Target.ValDate = Source.ValDate,
Target.ValuerID = Source.ValuerID,
Target.Amount = Source.Amount,
Target.Printed = Source.Printed,
Target.Approved = Source.Approved,
Target.Notes = Source.Notes,
Target.MultiplierValue = Source.MultiplierValue,
Target.MultiplierClass = Source.MultiplierClass,
Target.Adjustment = Source.Adjustment,
Target.SubmittedDate = Source.SubmittedDate
WHEN NOT MATCHED BY Target THEN
INSERT (
OwnerscorporationID,
ValDate,
ValuerID,
Amount,
Printed,
Approved,
Notes,
MultiplierValue,
MultiplierClass,
Adjustment,
SubmittedDate
)
VALUES (
Source.OwnersCorporationID,
Source.ValDate,
Source.ValuerID,
Source.Amount,
Source.Printed,
Source.Approved,
Source.Notes,
Source.MultiplierValue,
Source.MultiplierClass,
Source.Adjustment,
Source.SubmittedDate
);
END
I feel like I cheated but it's only one line so how bad can it be :)
In My SQL I added this line before the "SET NOCOUNT ON;"
(Funny if I put it after SET NOCOUNT ON I get a syntax error)
if (#ValuationID = 0) set #ValuationID = null
Then in my C# code I set the ID to 0 for a new record and it seems to work after a couple of tests. There may be a better way to do this but like most things in life you stop looking once it works.
Thanks again to those who commented.
David

How can I save a stored procedure which contains errors in SQL Server?

I want to save a stored procedure which contains errors according to SQL Server.
This is the procedure code:
Create PROCEDURE [Product].[JewelSearch]
#JewelItem bigint,
#JewelType nvarchar(50),
#JewelMate nvarchar(50)
AS
BEGIN
SET NOCOUNT ON;
SELECT *
FROM Product.#JewelType
WHERE Material = #JewelMate OR Item# = #JewelItem;
END
The problem is that I have a Product schema, and I am taking the table name from my main application and saving it in #JewelType and in each search in main application the table name must be changed and each time their will be a different table name in #JewelType.
According to me the query is perfect but SQL Server does not allow me to execute it and save it. Is there a way that I can forcibly save this stored procedure? Hope you understand my question please help me if possible.
If it is SQL Server, something like this should work
Create PROCEDURE [Product].[JewelSearch]
#JewelItem bigint,
#JewelType nvarchar(50),
#JewelMate nvarchar(50),
#SQL nvarchar(max)
AS BEGIN
SET NOCOUNT ON;
SET #SQL = 'Select * From Product.'+#JewelType+' where Material = '+#JewelMate+' OR Item# = '+CAST(#JewelItem as nvarchar(50))+'; '
EXEC(#SQL)
END
This is untested as I am on my Mac, but you get the idea.
If you are going to use this, be aware of the dangers of dynamic SQL in relation to SQL Injection.
SQL Injection with Dynamic SQL - MSDN

Stored Procedures and ASP .NET

i created a stored procedure on sql server for updating records,while there it works fine when I insert the required parameters... but when it comes to ASP .NET when I run the application when I press update on ASPX GridView it gives me a Message
"Procedure or function custUPDATE has too many arguments specified."
here is the code for my procedure
alter proc custUPDATE
( #odid int,
#customer_id int,
#priceID int,
#etAMOUNT int,
#amntPaid decimal(18,2),
#od_status varchar(20),
#py_status varchar(20),
#order_date smalldatetime
-- #dummy varchar(30) =null
)
as
begin
set nocount on;
declare #amnt_paid decimal(18,2);
declare #rmn decimal(23,4);
declare #tt money;
select #amnt_paid=eggsOrders.amnt_paid from eggsOrders where od_ID=#odid;
select #rmn= orderVIEW.Remaining from orderVIEW where od_ID=#odid;
select #tt=orderVIEW.Total from orderVIEW where od_ID=#odid;
--select #amnt_paid= amnt_paid from inserted;
if(#amnt_paid=#tt)
begin
update [dbo].[eggsOrders] set customer_ID=#customer_id, price_ID=#priceID, ET_amount=#etAMOUNT, amnt_paid=#amntPaid, Od_status=#od_status, py_status='paid in full', order_date=#order_date where od_ID=#odid;
end
else if(#amnt_paid>0 and #amnt_paid!=#tt)
begin
update [dbo].[eggsOrders] set customer_ID=#customer_id, price_ID=#priceID, ET_amount=#etAMOUNT, amnt_paid=#amntPaid, Od_status=#od_status, py_status='In-Progress', order_date=#order_date where od_ID=#odid
end
else if(#amnt_paid=0 and #rmn =#tt)
begin
update [dbo].[eggsOrders] set customer_ID=#customer_id, price_ID=#priceID, ET_amount=#etAMOUNT, amnt_paid=#amntPaid, Od_status=#od_status, py_status='Payment Pending', order_date=#order_date where od_ID=#odid
end
end
go
what am I doing wrong???
please help
The error is cristal clear: you're passing more parameters to the method than what it expect, causing the error. Review carefully how many parameters are you passing in the call to SP.
I’ve noticed occasionally that ASP.NET will cache the old SPROC in Visual Studio even after a change is made on SQL Server. So for example you changed custUPDATE by adding a parameter, and also added the parameter to your ASP.NET code, but are still receiving the “too many arguemtns specified” error because the old SPROC is being cached.
If this is the case I would try the following:
Change the SPROC name in your ASP.NET page from custUPDATE to [custUPDATE] and then try running it.

Parametrized stored procedure error

I am using SQL Server 2005 Management Studio Express. Coins and themes are my tables. I created a stored procedures using the above two and got struck with
Error:Msg 102, Level 15, State 1, Procedure themestat, Line 1
Incorrect syntax near 'id2'.
Here is my whole procedure:
create procedure themestat(id2 In numeric, id1 In numeric)
is
#userid nvarchar(50), #co nvarchar(50), #price nvarchar(50)
begin
update themes set prioirty=1 where themeid=id2;
select credits as co from coins where uid=id1;
select rate as price from themes where priority=1;
if(co>price)
begin
update themes set status=1 where priority=1;
update themes set priority=0 where themeid=id2;
end
else
begin
update themes set priority=0 where theme=id2;
PRINT 'no sufficient coins'
end
end
I am curious to know where I went wrong ??
I'm not sure where you've got the syntax from, but datatypes are declared as '#param type', so the first line should read:
create procedure themestat
#id2 numeric
#id1 numeric
Then obviously change all references of id1 and id2 as appropriate. There's other syntax errors in the script (missing declare, is instead of as, possibly others - I've not looked much closer).
This makes me wonder whether you've come from a different SQL dialect? I suggst reading about CREATE PROCEDURE on the MSDN (as well as other pages).

Resources