How to catch error occurred in SSIS - sql-server

I am calling a SSIS package inside procedure using xm_cmdshell. Below is the part of code from stored procedure.
DECLARE #ReturnCode INT
EXEC #ReturnCode=xp_cmdshell #cmd
IF #ReturnCode <>0
BEGIN
END
#cmd has the DTEXEC command to execute SSIS package.
If SSIS package fails I want to access SSIS error message inside IF clause. How can I achieve this?

To achieve what you want, use SSIS logging from within an SSIS package. For example you can log to a table. In your SQL script, you can read that table after calling xp_cmdshell to get errors.
Note also that MS is moving away from DTExec, look into SSIS catalog

Partially, you can achieve this following way:
DECLARE #output TABLE (lines varchar(2000))
DECLARE #ReturnCode INT
INSERT INTO #output
EXEC #ReturnCode=xp_cmdshell #cmd
IF #ReturnCode <>0
BEGIN
--do something with output
SELECT lines FROM #output WHERE lines IS NOT NULL
END
However, as #under mentioned, consider to use SSIS Catalog. in that case accomplishment of your task could be much simpler:
Start of SSIS package:
Declare #execution_id bigint
EXEC [SSISDB].[catalog].[create_execution] #package_name=N'Package.dtsx',
#execution_id=#execution_id OUTPUT,
#folder_name=N'Deployed Projects',
#project_name=N'Integration Services Project1',
#use32bitruntime=False,
#reference_id=Null
Select #execution_id
EXEC [SSISDB].[catalog].[start_execution] #execution_id
Querying for errors:
SELECT * FROM SSISDB.catalog.event_messages
WHERE operation_id = #execution_id AND event_name = 'OnError'

Related

Parameterize sp_add_jobstep for SSIS

From a TSQL Stored Procedure, I want to use the sp_add_jobstep stored procedure in the msdb database to create an SQL Agent job, which calls an SSIS package. I need to do this programmatically to dynamically set one of the parameters in the SSIS package at time of Job creation. In the "SQL Server Agent>Jobs>New Job" GUI, this is done under the "Steps>Edit>Configuration>Parameters" screen. How does one assign parameters with the sp_add_jobstep Stored Procedure?
The Microsoft documentation: https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-add-jobstep-transact-sql
does not explain this.
Related posts:
This post shows how to create an Agent job in T-SQL or C#: Create SQL Server Agent jobs programatically
And this post shows the SSIS syntax but does not discuss parameters: How do I create a step in my SQL Server Agent Job which will run my SSIS package?
As noted in the response by SAS, the params have to be passed as part of the command. The documentation for sp_add_jobstep shows a parameter called #additional_parameters, but notes this is not supported. So, while I didn't script it out (which would have been quicker), I did make an example job & then query the msdb.dbo.sysjobsteps table to see the format of the command. Based on that, and the earlier post by CSharper, I wrote the following stored procedure:
CREATE PROCEDURE [dbo].[CreateAgentjobHourlySSIS]
#job NVARCHAR(128),
#package NVARCHAR(max), -- \SSISDB\MyCatalog\MyProject\MyPackage.dtsx
#params NVARCHAR(max), -- /Par "\"$Project::MyParameter\"";ParameterValue /Par "\"$ServerOption::LOGGING_LEVEL(Int16)\"";1 /Par "\"$ServerOption::SYNCHRONIZED(Boolean)\"";True
#servername NVARCHAR(28),
#startdate DATE,
#starttime TIME,
#frequencyhours INT
AS
BEGIN TRY
BEGIN TRAN
--GRANT EXEC on CreateAgentjobHourlySSIS to PUBLIC
--1. Add a job
EXEC msdb.dbo.sp_add_job
#job_name = #job
--2. Add a job step named process step. This step runs the stored procedure
DECLARE #SSIScommand as NVARCHAR(max)
SET #SSIScommand = '/ISSERVER "\"'+#package+'\"" /SERVER "\"'+#servername+'\"" '+#params+' /CALLERINFO SQLAGENT /REPORTING E'
EXEC msdb.dbo.sp_add_jobstep
#job_name = #job,
#step_name = N'process step',
#subsystem = N'Dts',
#command = #SSIScommand
--3. Schedule the job starting at a specified date and time
DECLARE #startdateasint int = YEAR(#startDate)*10000+MONTH(#startdate)*100+DAY(#startdate)
DECLARE #starttimeasint int = DATEPART(HOUR,#starttime)*10000+DATEPART(MINUTE,#starttime)*100+DATEPART(SECOND,#starttime)
EXEC msdb.dbo.sp_add_jobschedule #job_name = #job,
#name = 'Hourly Schedule',
#freq_type = 4, --daily
#freq_interval = 1,
#freq_subday_type = 0x8, -- hourly
#freq_subday_interval = #frequencyhours,
#active_start_date = #startdateasint,
#active_start_time = #starttimeasint
--4. Add the job to the SQL Server
EXEC msdb.dbo.sp_add_jobserver
#job_name = #job,
#server_name = #servername
COMMIT TRAN
END TRY
BEGIN CATCH
SELECT ERROR_Message(), ERROR_Line();
ROLLBACK TRAN
END CATCH
You construct the call like this:
#command=N'/ISSERVER "
...
/Par "\"$Project::MyParam\"";ParamValue
...
If you already have a similar job you can right-click in SSMS and script it out.
That will show you the syntax.

Accessing 'Microsoft.ACE.OLEDB.12.0' from SQL Job Agent

I need to execute a stored procedure by job agent, that sp connects to 'Microsoft.ACE.OLEDB.12.0' and gets data from excel sheet.
when I execute sp, It's work. but when execute it by job agent it doesn't work.
My code is here:
First I wrote a return value procedure to get excel sheet name:
ALTER PROCEDURE [dbo].[spExcelSheetName]
#TableName nvarchar(250) output
AS
declare #table Table (TABLE_CAT nvarchar(50), TABLE_SCHEM nvarchar(50), TABLE_NAME nvarchar(50), TABLE_TYPE nvarchar(50), REMARKS nvarchar(50))
insert into #table
EXECUTE SP_TABLES_EX 'ExcelSource';
select #TableName = TABLE_NAME from #table
Then a sp for getting data from excel sheet and insert into my sql table:
ALTER PROCEDURE [dbo].[spConvertExcel]
AS
begin
IF EXISTS(SELECT * FROM sys.servers WHERE name = N'ExcelSource')
EXEC master.sys.sp_dropserver 'ExcelSource','droplogins'
EXEC sp_addlinkedserver 'ExcelSource', '',
'Microsoft.ACE.OLEDB.12.0',
'D:\Test\Personel.xlsx',
NULL,
'Excel 8.0'
EXEC sp_addlinkedsrvlogin 'ExcelSource', 'false'
EXEC sp_MSset_oledb_prop N'Microsoft.ACE.OLEDB.12.0', N'AllowInProcess', 1
declare #SheetName nvarchar(250)
exec spExcelSheetName #TableName = #SheetName OUTPUT
declare #Query nvarchar(max)
set #Query =
N'SELECT *
FROM OPENROWSET(''Microsoft.ACE.OLEDB.12.0'',
''Excel 12.0 Xml; HDR=YES;Database=D:\Test\Personel.xlsx'',
['+#SheetName+']);'
delete from ExcelPersonels
insert into ExcelPersonels
exec sp_executesql #Query;
delete from Personels
where personelcode in (select personelcode from ExcelPersonels)
update Personels set IsActive = 0
insert into Personels
select *, 1 from ExcelPersonels
end
This sp run without any problem, but when I want to run it by Job agent it doesn't work :(
job code is : exec (spConvertExcel)
Even I tried: osql –E –Q “exec spConvertExcel”
but it didn't work too.
error massage is:
Message
Executed as user: NT SERVICE\SQLAgent$SQL2014. Cannot initialize the data source object of OLE DB provider "Microsoft.ACE.OLEDB.12.0" for linked server "ExcelSource". [SQLSTATE 42000] (Error 7303) OLE DB provider "Microsoft.ACE.OLEDB.12.0" for linked server "ExcelSource" returned message "Unspecified error". [SQLSTATE 01000] (Error 7412). The step failed.
thanks for all replies.

Execute SSIS in SSMS

I have a SSIS package which will upload files into tables. I want to execute it as soon as a file has been uploaded and saved to a table. This link showed how to execute it using Stored Procedure. What I did was I created a trigger with the following code:
ALTER TRIGGER [dbo].[tr_ImportFile]
ON [dbo].[ReconMedicalAidFile]
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
DECLARE #params VARCHAR(MAX),
#ssisStr VARCHAR(MAX),
#packageName VARCHAR(MAX),
#serverName VARCHAR(MAX)
SET #serverName = 'ServerName'
SET #packageName = 'MyIntegration'
SET #ssisStr = 'dtexec /sq ' + #packageName + ' /ser ' + #serverName
DECLARE #returnCode int
EXEC #returnCode = xp_cmdshell #ssisStr
END
I get the following error Procedure expects parameter 'command_string' of type 'varchar'.
Any help would be appreciated.
Thanks
I think it works when you replace VARCHAR(MAX) with VARCHAR(8000) data types
I went a different route. Still have the trigger but it will execute a SQL Job which contains the SSIS package.
EXEC msdb.dbo.sp_start_job N'JobName' ;

SQL Job with TRY reports success on failure when inserting from remote SP

I've found a way to fail a SQL Scheduled Job (with severity 16) that does not report failure (and so does not send email notifications). I've fixed my immediate issue, but I want to know why there is a failure case that does not report as failure, and if there are any other surprising ways to miss notification.
I've set up two linked servers and am attempting to run an hourly scheduled SQL Job on one that queries the other. I found this morning that the code in the SP had not been running, but the history on the Job was reporting success. The Job's only step is EXEC _testSP. If I ran EXEC _testSP in a query window from SSMS, I received this error message:
Msg 0, Level 11, State 0, Line 0 A severe error occurred on the
current command. The results, if any, should be discarded.
The SP's contents are wrapped in TRY ... CATCH. If I remove the TRY ... CATCH, executing the SP gives up this error message:
Msg 213, Level 16, State 7, Line 1
Insert Error: Column name or number of supplied values does not match table definition.
This made sense. The remote table was referenced with a SELECT * FROM and some columns had been added to it. I've removed the asterix and the job runs fine now, but I want to make sure that all future exceptions get logged either by the job failure notification, or the CATCH block in _testSP. I don't understand why this one didn't get logged, and I hope that someone can explain it to me.
The job runs and fails and notifies just as I would expect when the TRY ... CATCH wrapping is removed, but we have some important things in the TRY ... CATCH that need to be kept.
This is not a duplicate of this related question. The Microsoft BOL for TRY...CATCH says that some exceptions cannot be caught by TRY...CATCH. It may be related, but what I've found is an exception that is not caught by the Scheduled Job agent.
Reproduceable example: (also try removing the TRY...CATCH wrapper and see the change)
USE [RemoteServer].[Database]
CREATE TABLE [Tally](
[ID] [int] IDENTITY(0,1) NOT NULL,
[ID2] [int] NOT NULL
) ON [PRIMARY]
GO
USE [LocalServer]
-- Setup procedure
CREATE PROCEDURE _testSP
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
-- Create destination temp table
CREATE TABLE #tempb (a int)
-- Insert into temp table from remote Tally table
DECLARE #query nvarchar(4000)
SELECT #query = '
SELECT TOP 5 *
FROM [Database].[dbo].Tally
'
INSERT INTO #tempb
EXEC [RemoteServer].[master].[dbo].sp_executesql #query
END TRY BEGIN CATCH
-- Log the exception
-- ...
-- Rethrow the exception
DECLARE #ErrorMessage nvarchar(max), #ErrorSeverity int, #ErrorState int;
SELECT
#ErrorMessage = 'Handled Exception: ' + ERROR_MESSAGE() + ' line ' + CAST(ERROR_LINE() as nvarchar(5)),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
RAISERROR (#ErrorMessage, #ErrorSeverity, #ErrorState);
END CATCH
END
GO
-- Setup job
DECLARE #database varchar(100)
SELECT #database = DB_Name()
EXEC msdb.dbo.sp_add_job
#job_name = '_testSPJob'
EXEC msdb.dbo.sp_add_jobstep
#job_name = '_testSPJob',
#step_name = '_testSPJob',
#subsystem = N'TSQL',
#command = 'EXEC _testSP',
#database_name = #database
EXEC msdb.dbo.sp_add_jobserver
#job_name = '_testSPJob',
#server_name = ##SERVERNAME
GO
-- Manual execution fails
EXEC _testSP
GO
-- Run job
EXEC msdb.dbo.sp_start_job
#job_name = '_testSPJob'
WAITFOR DELAY '00:00:02'
GO
-- Select job history
SELECT * FROM msdb.dbo.sysjobhistory
WHERE step_name = '_testSPJob'
ORDER BY run_date, run_time
GO
I really need to convince the bosses to get off SQL 2000. Here are my software versions. Perhaps this is fixed in later versions of SQL?
SSMS Version: 2012 (11.0.5058.0)
Local DB: SQL 2005 (9.0.5069)
Remote DB: SQL 2000 (8.0.760)
I think that what is happening is correct, because you're handdling an exception, so the job is not failling. A solution could be a log so when the exception y catch you insert a row with the error description.

Async Stored Procedure Call in T-SQL

How one can make an async call to a stored procedure from another one?
Assume I have two stored procedures, SP1 and SP2 (this is a long running stored procedure, takes much time to execute, and doesn't return any result).
The stored procedure SP1 is defined like this:
CREATE PROCEDURE SP1
AS
BEGIN
--custom business logic
--CALL to SP2, but async
EXEC SP2
END
How could you make a non-blocking/async call to SP like the above in SQL Server 2008/2012?
There was once I tried to achieve this by wrapping the stored procedure into Job, and then Calling the job in the procedure through sp_start_job system sp.
EXEC dbo.sp_start_job N'Job name' ;
Blockquote
Works as long as there are no arguments. – RoastBeast Dec 22 '15 at 17:30
Here's version with passing parameters
declare #variable -- job name
declare #command -- command
set #command = 'select * from table where data='+#variable
exec msdb..sp_add_job
#job_name =#variable,
#enabled=1,
#start_step_id=1,
#delete_level=1 --Job will delete itself after success
exec msdb..sp_add_jobstep
#job_name=#variable,
#step_id=1,
#step_name='step1',
#command=#command
exec msdb..sp_add_jobserver
#job_name = #variable,
#server_name = 'yourserver'
exec msdb..sp_start_job
#job_name=#variable

Resources