How do I look at SQL Agent Job without starting SQL Agent? - sql-server

I have just set up a new SQL Server instance on a new server and moved our application to use the new server. So I've had to turn SQL Agent off on the old server - turning it on would start the scheduler and start sending out emails and running things that shouldn't be run any more.
However, I need to take a close look at a SQL Agent Job on the old server, and ideally reverse-engineer the code to recreate it so I can modify it and apply it to the new server.
How do I generate the code for that Job on the old server without turning SQL Agent on?
Thanks

Even if SQL server agent is not running, you can see how jobs and schedules were set up by viewing the following system DMVs.
msdb.dbo.sysjobs_view
msdb.dbo.sysjobs
msdb.dbo.sysjobschedules
msdb.dbo.sysschedules
I use preset scripts to create all my jobs and schedules independent of the server. Here is a sample script to create the recycle log job. You can modify this or use any piece of this as you see fit.
DECLARE #sql nvarchar(max)
BEGIN TRY
IF EXISTS (SELECT job_id
FROM msdb.dbo.sysjobs_view
WHERE name = N'Cycle SQL log')
EXEC msdb.dbo.sp_delete_job #job_name=N'Cycle SQL log'
, #delete_unused_schedule=1
EXEC msdb.dbo.sp_add_job
#job_name = N'Cycle SQL log',
#description = N'This job forces SQL to start a new error log (In the Managment node of SSMS)',
#owner_login_name = N'your_sql_login' ;
EXEC msdb.dbo.sp_add_jobstep
#job_name = N'Cycle SQL log',
#step_name = N'sp_cycle_errorlog',
#subsystem = N'TSQL',
#command = N'exec sp_cycle_errorlog' --put your executable code here
--These next two lines set the target server to local, so that the job can be modified if necessary
SET #sql = 'EXEC msdb.dbo.sp_add_jobserver #job_name=N''Cycle SQL Log'', #server_name = N''' + ##SERVERNAME + ''''
EXEC sys.sp_executesql #stmt = #sql
END TRY
BEGIN CATCH
PRINT 'Uh-oh. Something bad happened when creating the Cycle SQL Log job. See the following error.'
PRINT CAST(ERROR_MESSAGE() AS NVARCHAR(1000))
END CATCH
You can use use code to automate the addition of schedules based on values you pull from the DMVs listed above.

Related

TSQL - Only execute a line if run manually (not in job)

Can I make an IF statement that only executes when run manually from SSMS?
I have a SQL Server job that executes TSQL code. That TSQL code is maintained in a separate .sql text file. When it needs to be edited, I edit the text file and copy&paste the final results into the job.
This normally works very well but there is one critical line that is only used for testing (it sets a variable to a specific value). How can I guarantee that line only executes when run manually?
Is there something like If ManualExecution() then Blah?
IF APP_NAME() LIKE 'Microsoft SQL Server Management Studio%'
BEGIN
PRINT 'Running inside SSMS'
END;
If you use SQL Agent to run the job, it's app name should be SQLAgent - TSQL JobStep (Job 0x... : Step ...). If you use some other software, just make sure that it doesn't set its Application Name to "Microsoft SQL Server Management Studio"...
You can use the following code to get the SQL Server Agent JobId of the current process (otherwise NULL):
declare #JobId as UniqueIdentifier;
begin try
-- The executed statement will result in a syntax error if not in a SQL Server Agent job.
execute sp_executesql
#stmt = N'select #JobId = Cast( $(ESCAPE_NONE(JOBID)) as UniqueIdentifier );',
#params = N'#JobId UniqueIdentifier output',
#JobId = #JobId output;
end try
begin catch
if ##Error != 102 -- 102 = Syntax error.
select ##Error; -- Handle unexpected errors here.
end catch
select #JobId as JobId; -- NULL if not running as a SQL Server Agent job.
Note that the JobId can be used to access additional information about the current job in dbo.sysjobs.

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.

Calling SSIS package from stored procedure under a different account

I have a stored procedure which runs and calls an SSIS pacakge using EXEC SSISDB.CATALOG.start_execution #Execution_Id method.
However I need the package to execute under a service account with more privileges and not the user's account.
using the EXECUTE AS LOGIN = doesn't work. Does anyone know how to accomplish this. The only other way I know involves Agent Jobs and proxy accounts.
Surely there is a simply way to accomplish this on SQL 2012 ?
'EXECUTE AS' works fine for me.
One thing to note is to switch context to the SSIS Catalog database, before calling the execute method. Hence the 'USE ' statement on top.
USE SSISDB;
EXECUTE AS LOGIN = 'domain\user'
DECLARE #execution_id BIGINT
EXEC CATALOG.create_execution #folder_name = 'MyFolder1',
#project_name = 'MyProject', #package_name = 'Package.dtsx',
#use32bitruntime = 1, #execution_id = #execution_id OUTPUT;
EXEC CATALOG.start_execution #execution_id;

Switching from one database to another within the same script

I would like to know how I can switch from one database to another within the same script. I have a script that reads the header information from a SQL Server .BAK file and loads the information into a test database. Once the information is in the temp table (Test database) I run the following script to get the database name.
This part works fine.
INSERT INTO #HeaderInfo EXEC('RESTORE HEADERONLY
FROM DISK = N''I:\TEST\database.bak''
WITH NOUNLOAD')
DECLARE #databasename varchar(128);
SET #databasename = (SELECT DatabaseName FROM #HeaderInfo);
The problem is when I try to run the following script nothing happens. The new database is never selected and the script is still on the test database.
EXEC ('USE '+ #databasename)
The goal is switch to the new database (USE NewDatabase) so that the other part of my script (DBCC CHECKDB) can run. This script checks the integrity of the database and saves the results to a temp table.
What am I doing wrong?
You can't expect a use statement to work in this fashion using dynamic SQL. Dynamic SQL is run in its own context, so as soon as it has executed, you're back to your original context. This means that you'd have to include your SQL statements in the same dynamic SQL execution, such as:
declare #db sysname = 'tempdb';
exec ('use ' + #db + '; dbcc checkdb;')
You can alternatively use fully qualified names for your DB objects and specify the database name in your dbcc command, even with a variable, as in:
declare #db sysname = 'tempdb';
dbcc checkdb (#db);
You can't do this because Exec scope is limited to dynamic query. When exec ends context is returned to original state. But context changes in Exec itself. So you should do your thing in one big dynamic statement like:
DECLARE #str NVARCHAR(MAX)
SET #str = 'select * from table1
USE DatabaseName
select * from table2'
EXEC (#str)

LoadFromSQLServer method has encountered OLE DB

I have this error:
LoadFromSQLServer method has encountered OLE DB error code 0x80004005 (Login timeout expired). The SQL statement that was issued has failed
And here is my code, what is wrong?
DECLARE #FileName VARCHAR(50);
DECLARE #VendorID VARCHAR(50);
DECLARE #sql VARCHAR(2000);
DECLARE #Local_File_FullPath VARCHAR(100);
SET #FileName = 'Extgt_skinny_file.txt.pgp'
Set #VendorID = 'ET'
Select #Local_File_FullPath = dw03_path FROM GMAC_META.dbo.VENDOR_XFER_METADATA where vendor_id = #VendorID
SET #sql = 'dtexec /SQL "\EMAP_FTP_XFER_CHECK" /SET \Package.Variables[User::FileName].Properties[Value];"'
+ #FileName+'" /SET \Package.Variables[Local_File_FullPath].Properties[Value];'
+ #Local_File_FullPath+' /SERVER "hqgmdw02/dw_dev" /CHECKPOINTING OFF /REPORTING E'
exec xp_cmdshell #sql
Try the following:
GRANT exec ON xp_cmdshell TO '<somelogin>'. Please refer to xp_cmdshell (Transact-SQL).
Check to see if you are using a 32-bit DTExec on a 64-bit machine.
Ensure that the users that will run the SSIS package have sufficient permissions. I take that you run is under SSIS in a SQL Server Agent or you might run it manually. The service account running SQL Agent and your account must have permissions to execute the job. Please see Error in executing SSIS package through Agent
As the OP mentioned, the server routes (for parameter /SERVER) should use backslashes and not common slashes. The error being displayed is a little misleading for this occasion, as the login times out because the server path is incorrect.
So change
/SERVER "hqgmdw02/dw_dev"
for
/SERVER "hqgmdw02\dw_dev"

Resources