My SQL Server instance has an agent job called Grand Master that runs to a schedule every minute, 24/7.
I have created another job that needs to be run manually from time to time. One of the first things it needs to do is disable and stop the Grand Master job from running while it is active.
Step 1 is to disable the GM, which works fine:
exec msdb..sp_update_job #job_name = "Grand Master", #Enabled = 0
Step 2, however fails. Its job it to stop the GM from running IF it is running. It is not supposed to do anything if the GM is not currently running:
if exists (select 1
from msdb.dbo.sysjobs_view j
join msdb.dbo.sysjobactivity a on j.job_id = a.job_id
where a.run_requested_date is not null
and a.stop_execution_date is null
and j.name = 'Grand Master')
begin
exec msdb.dbo.sp_stop_job 'Grand Master'
end
Every time I run this job, regardless of the state of the GM, it fails on step 2 with this error:
Executed as user: NT AUTHORITY\SYSTEM. SQLServerAgent Error: Request to stop job Grand Master (from User NT AUTHORITY\SYSTEM) refused because the job is not currently running. [SQLSTATE 42000] (Error 22022). The step failed.
Does anyone have any ideas?
First stop it if it's running and then disable the job. SQL Server might misinterprete the idea to stop a disabled job...
If you have a disordered working environment, the above query may show different results than Job Activity Monitor (imho, GUI info is more reliable). You can use the next procedure to check if a job is in "Executing" state. The procedure is provided at your own responsibility.
/*
procedure result: 0=Not idle or suspended, 1=Executing, 2=WaitingForThread, 3=BetweenRetries, 4=Idle, 5=Suspended, [6=WaitingForStepToFinish], 7=PerformingCompletionActions
*/
CREATE PROCEDURE [dbo].[sp_get_job_state] (
#job_name VARCHAR(100)
, #job_state SMALLINT OUTPUT
)
AS
BEGIN
DECLARE #job_id UNIQUEIDENTIFIER
, #can_see_all_running_jobs INT = 1
, #job_owner SYSNAME = SUSER_SNAME()
, #res SMALLINT;
DECLARE #xp_results TABLE (
job_id UNIQUEIDENTIFIER NOT NULL
, last_run_date INT NOT NULL
, last_run_time INT NOT NULL
, next_run_date INT NOT NULL
, next_run_time INT NOT NULL
, next_run_schedule_id INT NOT NULL
, requested_to_run INT NOT NULL
, -- BOOL
request_source INT NOT NULL
, request_source_id SYSNAME COLLATE database_default NULL
, running INT NOT NULL
, -- BOOL
current_step INT NOT NULL
, current_retry_attempt INT NOT NULL
, job_state INT NOT NULL
);
SELECT #job_id = job_id
FROM msdb..sysjobs
WHERE name = #job_name;
INSERT INTO #xp_results (
job_id
, last_run_date
, last_run_time
, next_run_date
, next_run_time
, next_run_schedule_id
, requested_to_run
, request_source
, request_source_id
, running
, current_step
, current_retry_attempt
, job_state
)
EXECUTE master.dbo.xp_sqlagent_enum_jobs #can_see_all_running_jobs = #can_see_all_running_jobs
, #job_owner = #job_owner
, #job_id = #job_id;
SELECT #job_state = job_state
FROM #xp_results
END
Related
I am working in a SQL Server environment with one master server and many target servers. It sometimes happens that for a reason or another one a target server may go out of sync.
I have the choice when that occurs to manually run the following stored procedure to re-sync the target server:
exec sp_resync_targetserver #server_name = 'RMAPP11DV1\PROJECT'
My assignment is to automate the process so that we do not have to manually run it. I should write a script and schedule it as a job that should run a a schedule time to selectively find and re-sync only the target servers that are currently out of sync.
This is my approach so far. It is not working as expected (can not do the re-sync when ran), that is why I need any one output. Thanks in advance:
use msdb
set nocount on;
if exists (select * from tempdb.sys.all_objects where name like '%#targetstatus%') --deleting the table if it already exists
drop table #targetstatus
create table #targetstatus
(
server_id int not null,
server_name nvarchar(300) not null,
location nvarchar(350) null,
time_zone_adjustment int not null,
enlist_date datetime not null,
last_poll_date datetime not null,
status int not null,
unread_instructions int not null,
local_time datetime not null,
enlisted_by_nt_user nvarchar(100) not null,
poll_interval int not null
)
insert into #targetstatus
exec sp_help_targetserver
select * from #targetstatus
if exists (select * from tempdb.sys.all_objects where name like '%#needresync%') --deleting the table if it already exists
drop table #needresync
create table #needresync -- will hold the target servers needing to be re-synced
(
server_id int not null,
server_name nvarchar(300) not null,
location nvarchar(350) null,
time_zone_adjustment int not null,
enlist_date datetime not null,
last_poll_date datetime not null,
status int not null,
unread_instructions int not null,
local_time datetime not null,
enlisted_by_nt_user nvarchar(100) not null,
poll_interval int not null
)
insert into #needresync
select *
from #targetstatus
where status <> 1 -- we only want to run the syncing proc on the target with a status diff of #1
select * from #needresync
declare #target_server varchar(100);
set #target_server = ' '
while #target_server <> ' '
begin
set #target_server = (select max(server_name) from #needresync);
exec msdb.dbo.sp_resync_targetserver #server_name = '#target_server';
-- #target_server = #target_server + 1
end
You are not deleting the row out of #needresync. You must delete each row one by one inside the while loop.
However, a much easier method exists. You can use the systargetservers DMV without using any temp tables at all:
DECLARE #server sysname =
(SELECT TOP 1 FROM dbo.systargetservers WHERE status = 2); -- 2 = Re-sync Pending
WHILE (#server IS NOT NULL)
BEGIN
EXEC sp_resync_targetserver #server;
SET #server =
(SELECT TOP 1 FROM dbo.systargetservers WHERE status = 2);
END;
Let's say I have a table called [dbo].[Order] in my MSSQL Server database like the following:
CREATE TABLE [dbo].[Order] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[NumberInMonth] INT NOT NULL,
[Amount] DECIMAL (18, 2) NOT NULL,
CONSTRAINT [PK_dbo.Order] PRIMARY KEY CLUSTERED ([Id] ASC)
);
I want to have NumberInMonth column to be:
auto-incremented, so that the database will guarantee that the INSERT operation will create a new record with the value of Number = < previous value of Number > + 1 without any effort on the side of the application code
not unique, so that i could have one order #18 in January and another one order #18 in February (which will differ by Id field)
And also I'd like to have a way to have a schedulled operation which will reset the counter of NumberInMonth every first day of a month
How do I achieve it?
A simple sequence can provide the auto-incrementing functionallity:
CREATE SEQUENCE seq_numberInMonth as int START WITH 1 INCREMENT BY 1;
CREATE TABLE [dbo].[Order] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[NumberInMonth] INT NOT NULL DEFAULT(next value for seq_numberInMonth),
[Amount] DECIMAL (18, 2) NOT NULL,
CONSTRAINT [PK_dbo.Order] PRIMARY KEY CLUSTERED ([Id] ASC)
);
Test:
INSERT INTO [Order] (Amount) VALUES (12.0), (13.0), (14.0)
SELECT *
FROM [Order]
results:
Id NumberInMonth Amount
1 1 12,00
2 2 13,00
3 3 14,00
You can quite easily create a scheduled job to run every 1st of the month and reset the sequence:
ALTER SEQUENCE seq_numberInMonth RESTART WITH 1 ;
Creating the job in t-sql can be done like this: (didn't test it, but it should work according to the following links):
How to: Create a SQL Server Agent Job
Create a Job
USE msdb ;
GO
EXEC dbo.sp_add_job
#job_name = N'seq_numberInMonth reset' ;
GO
EXEC sp_add_jobstep
#job_name = N'seq_numberInMonth reset',
#step_name = N'1st',
#subsystem = N'TSQL',
#command = N'ALTER SEQUENCE seq_numberInMonth RESTART WITH 1 ;',
#retry_attempts = 5,
#retry_interval = 5 ;
GO
EXEC sp_add_schedule #schedule_name = 'every 1st of the month'
, #enabled = 1
, #freq_type = 16
, #freq_interval = 1
GO
EXEC sp_attach_schedule
#job_name = N'seq_numberInMonth reset',
#schedule_name = N'every 1st of the month';
GO
EXEC dbo.sp_add_jobserver
#job_name = N'seq_numberInMonth reset';
GO
How to find which query is consuming more space in temp db in SQL 2000 version. I do not want to use SQL profiler as there is not much space on disk.
Issue is its 2000 version. No information can be pulled using dmv's.
How to track that between 1-2 which query and on which database is making tempdb size to grow as much that notifications are coming that could allocate page under tempdb, it is full.
You can create a proc out of the script below which can be executed by a job. More or less this is a template and can be altered however you see fit.
EDIT: Added additional comments below.
--Create temp table for sysprocesses records
IF OBJECT_ID('tempdb.dbo.#SYSPROC') IS NOT NULL
DROP TABLE #SYSPROC;
BEGIN
CREATE TABLE #SYSPROC
(
spid smallint NOT NULL,
dbid smallint NOT NULL,
blocked smallint NOT NULL,
lastwaittype nchar(32) NOT NULL,
cpu int NOT NULL,
physical_io int NOT NULL,
memusage int NOT NULL,
login_time datetime NOT NULL,
Last_batch datetime NOT NULL,
status nchar(30) NOT NULL,
cmd nchar(16) NOT NULL,
loginame nchar(128) NOT NULL,
sql_handle binary(20) NOT NULL,
sh_text text NULL,
snapshot_dt datetime NULL
)
END;
--Insert sysprocesses records into temp #SYSPROC
INSERT INTO #SYSPROC
(
spid,
dbid,
blocked,
lastwaittype,
cpu,
physical_io,
memusage,
login_time,
Last_batch,
status,
cmd,
loginame,
sql_handle,
snapshot_dt
)
SELECT
sp.spid,
sp.dbid,
sp.blocked,
sp.lastwaittype,
sp.cpu,
sp.physical_io,
sp.memusage,
sp.login_time,
sp.Last_batch,
sp.status,
sp.cmd,
sp.loginame,
sp.sql_handle,
GETDATE()
FROM master.dbo.sysprocesses sp
WHERE sp.spid > 50;
/*
Update temp #SYSPROC with sql text. Since CROSS APPLY is not
available in SQL Server 2000, a loop is required to interate
through each record.
*/
DECLARE #min_spid smallint = (SELECT MIN(spid) FROM #SYSPROC);
DECLARE #max_spid smallint = (SELECT MAX(spid) FROM #SYSPROC);
DECLARE #sql_handle binary(20);
DECLARE #sql_text varchar(max);
WHILE #min_spid <= #max_spid
BEGIN
--Set #sql_handle variable to be evaluated by the fn_get_sql function
SELECT
#sql_handle = S.sql_handle
FROM #SYSPROC S
WHERE spid = #min_spid
--Identify the sql_text for the session by passing the #sql_handle variablet through fn_get_sql
SELECT
#sql_text = H.text
FROM fn_get_sql(#sql_handle) H
--Update #SYSPROC with the sql_text.
UPDATE S
SET sh_text = #sql_text
FROM #SYSPROC S
WHERE spid = #min_spid
SET #min_spid = #min_spid + 1
END;
INSERT INTO <SOMETABLE YOU CREATE>
(
spid,
dbid,
blocked,
lastwaittype,
cpu,
physical_io,
memusage,
login_time,
Last_batch,
status,
cmd,
loginame,
sql_handle,
snapshot_dt
)
SELECT
spid,
dbid,
blocked,
lastwaittype,
cpu,
physical_io,
memusage,
login_time,
Last_batch,
status,
cmd,
loginame,
sql_handle,
snapshot_dt
FROM #SYSPROC
Hope this helps!
I am having issue with calling a SQL procedure from dexterity. The procedure contains cursor. This cursor is suppose to call another procedure which has a call to Dynamics GP Procedure 'taComputerChecklineinsert'. The working is supposed to be that the overall process has to insert transactions in the payroll transaction entry. Only a fixed number of 42 transactions get inserted. I have more than 42 transactions. If i execute the same procedure from SQL server with the same parameters itself it gives the required result. the issue comes up when i call from dexterity. what could be wrong?...i have been on this for long....and cannot figure out the issue.
Resolved finally. It has got nothing to go with any of the two econnect procedures namely 'taCreatePayrollBatchHeaderInsert' and 'taComputerChecklineinsert'.
It had raised due to a select statement before the batch creation by taCreatePayrollBatchHeaderInsert. the select statement was in place to select the parameters for taCreatePayrollBatchHeaderInsert.
The code worked perfectly fine when the select statement was commented.
CREATE PROC [dbo].[GTG_PR_Create_ABS_Trx]
#CMPANYID INT
, #UPRBCHOR INT -- 1 = Computer Check , 2 = Manual Check
, #BACHNUMB CHAR(15)
, #EMPLOYID CHAR(15)
, #COMPTRTP SMALLINT -- Computer transaction type:1 = Pay code; 2 = Deduction; 3 = Benefit
, #SALCHG SMALLINT -- Salary change ; required if passing a salary pay code:1 = Reallocate dollars; 2 = Reallocate hours;3=Reduce dollars;4=Reduce hours;=5=Additional amount
, #UPRTRXCD CHAR(6) -- (OT , ABS)
, #TRXBEGDT DATETIME
, #TRXENDDT DATETIME
, #Amount NUMERIC(19 , 5) -- Amount
, #ProcessStatus INT OUT
, #ErrorState INT OUT
, #ErrString VARCHAR(255) OUT
AS
set #ErrorState = 0
set #ErrString = ''
-- Create batch if it doesn`t exist
IF NOT EXISTS( SELECT 1 FROM DYNAMICS..UPR10304 WHERE BACHNUMB = #BACHNUMB AND CMPANYID = #CMPANYID AND UPRBCHOR = #UPRBCHOR )
BEGIN
**--SELECT #BACHNUMB
-- ,#UPRBCHOR
-- ,#ErrorState
-- ,#ErrString**
EXEC taCreatePayrollBatchHeaderInsert
#I_vBACHNUMB = #BACHNUMB
, #I_vUPRBCHOR = #UPRBCHOR
, #O_iErrorState = #ErrorState OUT
, #oErrString = #ErrString OUT
-- Associate employee deduction code if association doesn`t exist
IF NOT EXISTS(SELECT 1 FROM UPR00500 WHERE EMPLOYID = #EMPLOYID AND DEDUCTON = #UPRTRXCD)
BEGIN
EXEC taCreateEmployeeDeduction
#I_vEMPLOYID = #EMPLOYID
, #I_vDEDUCTON = #UPRTRXCD
, #O_iErrorState = #ErrorState OUT
, #oErrString = #ErrString OUT
END
-- Create Transaction
EXEC taCreateComputerCheckLineInsert
#I_vBACHNUMB = #BACHNUMB
, #I_vEMPLOYID = #EMPLOYID
, #I_vCOMPTRTP = #COMPTRTP
, #I_vSALCHG = #SALCHG
, #I_vUPRTRXCD = #UPRTRXCD
, #I_vTRXBEGDT = #TRXBEGDT
, #I_vTRXENDDT = #TRXENDDT
, #I_vVARDBAMT = #Amount
, #O_iErrorState = #ErrorState OUT
, #oErrString = #ErrString OUT
END
GO
Afternoon. I have several SQL Agent jobs running on an MS 2K8 BI server, some of them on a daily basis, others hourly, and one every two minutes (a heartbeat monitor for another process). There is also an app which imports data every few minutes, around the clock. Occasionally some combination of updates and reports collide and one or another hangs for a half hour or more, instead of the usual 60 seconds.
While I need to get to the root of these race conditions, in the meantime I'd like to set certain jobs to automatically die after, say, five minutes. I can do this in SSIS or a Windows scheduled task, but I don't see any way to do so in SQL Agent. Is this possible, or do I need to wrap the task in an SSIS package to get this kind of control?
FYI, here's the SQL Agent job I ended up using:
DECLARE #Cancelled BIT
EXEC dbo.CancelJob #JobName = 'ETL - Daily', #Cancelled = #Cancelled OUT
IF #Cancelled = 1
BEGIN
DECLARE #Success INT
EXEC #Success = msdb..sp_send_dbmail
#profile_name = 'Reporting',
#recipients = 'reporting#mycompany.com',
#subject = 'Cancelled Daily ETL'
IF #Success <> 0 RAISERROR('An error occurred while attempting to send an e-mail.', 16, #Success)
END
...and here's the code behind CancelJob:
CREATE PROCEDURE dbo.CancelJob(#JobName VARCHAR(100), #OwnerName VARCHAR(100) = NULL, #Cancelled BIT OUT)
AS BEGIN
IF #OwnerName IS NULL SET #OwnerName = SUSER_NAME()
SET #Cancelled = 0
CREATE TABLE #JobInfo
(
Job_ID UNIQUEIDENTIFIER,
Last_Run_Date INT,
Last_Run_Time INT,
Next_Run_Date INT,
Next_Run_Time INT,
Next_Run_Schedule_ID INT,
Requested_To_Run INT,
Request_Source INT,
Request_Source_ID VARCHAR(100),
Running INT, -- This is the only field we want (sigh)
Current_Step INT,
Current_Retry_Attempt INT,
State INT
)
INSERT INTO #JobInfo
EXEC xp_sqlagent_enum_jobs 1, #OwnerName
DECLARE #Running INT = (SELECT Running FROM #JobInfo AS JI INNER JOIN msdb..sysjobs_view AS J ON JI.Job_ID = J.job_id WHERE J.name = #JobName)
IF #Running = 1
BEGIN
BEGIN TRY
EXEC msdb..sp_stop_job #job_name = #JobName
SET #Cancelled = 1
END TRY
BEGIN CATCH
-- If an error occurs, it is *probably* because the job finished before we could cancel it, which is fine
END CATCH
END
END
GO
xp_sqlagent_enum_jobs was the trick to avoid the uncatchable error.
I have never had to do this frequently, so there may be better long-term solutions, but I have created a second job to stop the first on the rare occasions that I had to perform this task. I just used the sp_stopjob procedure to do this.