Задания агента SQL могут выполняться параллельно и создаваться непосредственно из TSQL.Ответ Ремуса Русану содержит ссылку, в которой упоминается об этом наряду с некоторыми недостатками.
Другим недостатком является то, что для создания задания требуются дополнительные разрешения безопасности.Кроме того, для реализации, представленной ниже, задание должно выполняться как определенный пользователь + вход в систему с дополнительными привилегиями управления заданиями.
Возможно запустить произвольный SQL от имени другого (более безопасного) пользователя, однако я считаю, что для назначения задания ему необходима привилегия sysadmin.
Возвращенный @pJobIdHexOut может использоваться для остановкиработа при необходимости.
create proc [Common].[usp_CreateExecuteOneTimeBackgroundJob]
@pJobNameKey varchar(100), -- Caller should ensure uniqueness to avoid a violation
@pJobDescription varchar(1000),
@pSql nvarchar(max),
@pJobIdHexOut varchar(100) = null out, -- JobId as Hex string. For SqlServer 2014 binary(16) = varchar(64)
@pDebug bit = 0 -- True to include print messages
--
with execute as 'TSqlBackgroundJobOwner' -- requires special permissions (See below)
as
/*---------------------------------------------------------------------------------------------------------------------
Purpose: Create a one time background job and launch it immediately. The job is owned by the "execute as" UserName
Caller must ensure the @pSql argument is safe.
Required Permissions for "execute as" user:
-- User must be created with associated login (w/ deny connect).
use [msdb];
create user [$UserName$] for login [$LoginName$];
alter role [SQLAgentUserRole] add member [$UserName$];
alter role [SQLAgentReaderRole] add member [$UserName$];
alter role [SQLAgentOperatorRole] add member [$UserName$];
grant select on dbo.sysjobs to [$UserName$];
grant select on dbo.sysjobactivity to [$UserName$];',
use [Master];
create user [$UserName$] for login [$LoginName$];
grant execute on xp_sqlagent_is_starting to [$UserName$];
grant execute on xp_sqlagent_notify to [$UserName$];';
Modified By Description
---------- ----------- ------------------------------------------------------------------------------------------
2014.08.22 crokusek Initial version
2015.12.22 crokusek Use the SP caller as the job owner (removed the explicit setting of the job owner).
---------------------------------------------------------------------------------------------------------------------*/
begin try
declare
@usp varchar(100) = object_name(@@procid),
@currentDatabase nvarchar(100) = db_name(),
@jobId binary(16),
@jobOwnerLogin nvarchar(100);
set xact_abort on; -- ensure transaction is aborted on non-catchables like client timeout, etc.
begin transaction
exec msdb.dbo.sp_add_job
@job_name=@pJobNameKey,
@enabled=1,
@notify_level_eventlog=0,
@notify_level_email=2,
@notify_level_netsend=2,
@notify_level_page=2,
@delete_level=3,
@description=@pJobDescription,
@category_name=N'Database Maintenance',
-- If not overridden then the the current login is the job owner
--@owner_login_name=@jobOwnerLogin, -- Requires sysadmin to set this so avoiding.
@job_id = @jobId output;
-- Get the job_id string of the jobId (special format)
--
set @pJobIdHexOut = Common.ufn_JobIdFromHex(@jobId);
if (@pDebug = 1)
begin
print 'JobId: ' + @pJobIdHexOut;
print 'Sql: ' + @pSql;
end
exec msdb.dbo.sp_add_jobserver @job_id=@jobId; -- default is local server
exec msdb.dbo.sp_add_jobstep
@job_id=@jobId,
@step_name=N'One-Time Job Step 1',
@step_id=1,
@command=@pSql,
@database_name=@currentDatabase,
@cmdexec_success_code=0,
@on_success_action=1,
@on_fail_action=2,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0,
@subsystem=N'TSQL',
@flags=0
;
declare
@startResult int;
exec @startResult = msdb.dbo.sp_start_job
@job_id = @jobId;
-- End the transaction
--
if (@startResult != 0)
raiserror('Unable to start the job', 16, 1); -- causes rollback in catch block
else
commit; -- Success
end try
begin catch
declare
@CatchingUsp varchar(100) = object_name(@@procid);
if (xact_state() = -1)
rollback;
--exec Common.usp_Log
-- @pMethod = @CatchingUsp;
--exec Common.usp_RethrowError
-- @pCatchingMethod = @CatchingUsp;
end catch