SQL Job Status - sql

I am actually working on SP in SQL 2005. Using SP i am creating a job and am scheduling it for a particular time. These jobs take atleast 5 to 10 min to complete as the database is very huge. But I am not aware of how to check the status of the Job. I want to know if it has got completed successfully or was there any error in execution. On exception i also return proper error code. But i am not aware of where i can check for this error code.

This is what I could find, maybe it solves your problem:
SP to get the current job activiity.
exec msdb.dbo.sp_help_jobactivity #job_id = (your job_id here)
You can execute this SP and place the result in a temp table and get the required result from there.
Otherwise have a look at these tables:
msdb.dbo.sysjobactivity
msdb.dbo.sysjobhistory
Run the following to see the association between these tables.
exec sp_helptext sp_help_jobactivity

--Copy in Query analizer and format it properly so you can understand it easyly
--To execute your task(Job) using Query
exec msdb.dbo.sp_start_job #job_name ='Job Name',#server_name = server name
-- After executing query to check weateher it finished or not
Declare #JobId as varchar(36)
Select #JobId = job_id from sysjobs where name = 'Your Job Name'
Declare #JobStatus as int set #JobStatus = -1
While #JobStatus <= -1
Begin
--Provide TimeDelay according your Job
select #JobStatus = isnull(run_status ,-1)
from sysjobactivity JA,sysjobhistory JH
where JA.job_history_id = JH.instance_id and JA.job_id = #JobId
End
select #JobStatus
null = Running
1 = Fininshed successfully
0 = Finished with error
--Once your Job will fininsh you'll get result

I got a better code from here
Use msdb
go
select distinct j.Name as "Job Name", j.description as "Job Description", h.run_date as LastStatusDate,
case h.run_status
when 0 then 'Failed'
when 1 then 'Successful'
when 3 then 'Cancelled'
--when 4 then 'In Progress'
end as JobStatus
from sysJobHistory h, sysJobs j
where j.job_id = h.job_id and h.run_date =
(select max(hi.run_date) from sysJobHistory hi where h.job_id = hi.job_id)
order by 1

Related

Conditional query with a parameter stored procedure

I'm learning SQL so I don't know yet all the subtlety of the language,
I wrote the following stored procedure (simplified here):
ALTER PROCEDURE [dbo].[SelectAllIssues]
#Status nvarchar(1) = 0
AS
BEGIN
SET NOCOUNT ON;
IF #Status = 1 OR #Status = 2
BEGIN
SELECT IssueStatuses.Id AS 'StatusId'
FROM Issues
INNER JOIN IssueStatuses ON Issues.IssueStatusId = IssueStatuses.Id
WHERE Issues.IssueStatusId = #Status
ORDER BY Created
END
ELSE
BEGIN
SELECT IssueStatuses.Id AS 'StatusId'
FROM Issues
INNER JOIN IssueStatuses ON Issues.IssueStatusId = IssueStatuses.Id
ORDER BY Created
END
END
But it doesn't look like a natural way to do that and there is a lot of repeated code.
I want to avoid something like
EXEC sp_executesql #sqlStrComplet
But if it's the only way.
I don't know the correct tag but sqllocaldb info MSSQLLocalDB return
Version : 13.1.4001.0
and I use SQL Server Management Studio (SSMS)
Just:
select s.Id as StatusId
from issues i
inner join IssueStatuses s on i.IssueStatusId = s.Id
where (i.IssueStatusId = #Status and #status in (1, 2)) or #status not in (1, 2)
Order By created
The where clause can be simplified:
where i.IssueStatusId = #Status or #status not in (1, 2)

Notifications for SQL Job when a step fails

Trying to find out if there is a way to setup email notifications when just 1 (or more) steps fail on a sql job. I have a job with 9 steps, but each step needs to be set to continue to next step even if it fails. So even when a step fails, because I need it to go to the next step its not set to "report failure". As SQL Server Agent does not have an option for "Report failure and go to next step" I am wondering if anyone has any workarounds for getting a notification
You can add an additional job step to query the msdb tables for steps that failed. After this, the sp_send_dbmail stored procedure can be used to send an email with the errors if any occurred. The run_date column of SYSJOBHISTORY is an int column, so the date will be along the format of YYYYMMDD. The filter below on the run_status column will apply to individual steps regardless of the overall job outcome, with 0 indicating a status of failed.
DECLARE #JobExecutionDate INT
--current date
SET #JobExecutionDate = CAST(CONVERT(VARCHAR(8),GETDATE(),112) AS INT)
--check if there were any errors first
IF EXISTS (SELECT h.instance_id
FROM MSDB.DBO.SYSJOBHISTORY h
INNER JOIN MSDB.DBO.SYSJOBS j ON h.job_id = j.job_id
INNER JOIN MSDB.DBO.SYSJOBSTEPS s ON j.job_id = s.job_id AND h.step_id = s.step_id
WHERE h.run_status = 0 AND h.run_date = #JobExecutionDate AND j.name = 'YourJobName')
BEGIN
DECLARE #Title VARCHAR(50)
SET #Title = CONCAT(CONVERT(VARCHAR(12), CAST(GETDATE() AS DATE), 109), ' Job Error Email')
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'Your Database Mail Profile',
#recipients = 'ExampleEmail#Domain.com',
#query = 'SELECT j.[name] AS JobName,
s.step_name AS StepName,
h.run_date AS RunDate,
h.run_time AS RunTime,
h.sql_severity As ErrorSeverity,
h.message AS ErrorMessage
FROM MSDB.DBO.SYSJOBHISTORY h
INNER JOIN MSDB.DBO.SYSJOBS j ON h.job_id = j.job_id
INNER JOIN MSDB.DBO.SYSJOBSTEPS s ON j.job_id = s.job_id AND h.step_id = s.step_id
WHERE h.run_status = 0 AND h.run_date = CAST(CONVERT(VARCHAR(8),GETDATE(),112) AS INT) AND j.name = ''YourJobName''
',
#query_result_no_padding = 1,
#subject = #Title ;
END

Strange exec and sp_executesql different behavior

I have a small stored procedure (SQl Server 2012).
IF I run it using:
exec spSelRegion #bOver21 = 1
I Get different results than if I run it using:
exec sp_executesql N'spSelRegion',N'#bOver21 bit',#bOver21=1
What is the difference?
ALTER PROCEDURE [dbo].[spSelRegion]
(
#ID int = NULL
,#Name varchar(128) = NULL
,#OrderBy varchar(16) = 'ID'
,#bOver21 bit = null
)
AS
SELECT distinct
r.[ID],
r.[Name],
r.[dInserted],
r.[sInserted],
r.[dUpdated],
r.[sUpdated],
r.[timestamp]
FROM
[dbo].[tblRegion] r
left outer join tblCountyRegion cr
on r.ID = cr.RegionNbr
WHERE
(r.[ID] = #ID or #ID is null)
AND (r.[Name] = #Name or #Name is null)
AND (#bOver21 is null and r.[ID] >20
OR (#bOver21 = 1 and r.[ID] > 20 and cr.IsActive=1)
OR (#bOver21 = 0 and r.[ID] >= 21 and r.id < 31))
I don't want to make this more complecated than it is . But after a microsoft update today , some stored procedures are now runnig using sp_executesql instead of Exec and this is source of the issue.
You would need to run your dynamic SQL with the parameter specified. Without that, it assumes a null value passed. So this:
exec sp_executesql N'spSelRegion #bOver21 = #bOver21',N'#bOver21 bit',#bOver21=1

Retrieving the Name of Running Stored Procedures Across Multiple Databases

I'm trying to write a query that reports the current database activity. The query links together various DMV's like sys.dm_exec_connections, sys.dm_exec_sessions, sys.dm_exec_requests, etc. The query also pulls the actual queries being run via the sys.dm_exec_sql_text function.
(I'm aware of Activity Monitor and SQL Profiler. I need to gather this information up in a query, so neither of these programs are relevant here.)
Much of the activity in our systems takes place in stored procedures and functions. It would be nice to see the names of these procedures in this query.
My question is:
How do I reliably display the name of the stored procedures or functions being executed?
I'm aware that the sys.dm_exec_sql_text function returns an objectid, and that I can join this objectid to sys.objects. The problem is, there are multiple databases on this server, and sys.objects only applies to the current database. I want this query to be able to show the running object name no matter what database the query happened to be run against.
So far the only solution I have is to use sp_msforeachdb create a temp table containing all the object IDs and names from all databases and join to this table from the result of the dm_exec_sql_text function.
Is there a better solution to the temp table approach? I feel like I'm missing something.
I would recommend Adam Machanic's excellent sp_WhoISActive. It doesn't return the exact object name, but does return the sql command being executed in a nice clickable form.
--I use the following proc:
USE [master]
GO
CREATE PROC [dbo].[sp_who3]
AS
SET NOCOUNT ON
DECLARE #LoginName varchar(128)
DECLARE #AppName varchar(128)
SELECT [SPID] = s.[spid]
, [CPU] = s.[cpu]
, [Physical_IO] = s.[physical_io]
, [Blocked] = s.[blocked]
, [LoginName] = CONVERT([sysname], RTRIM(s.[Loginame]))
, [Database] = d.[name]
, [AppName] = s.[program_name]
, [HostName] = s.[hostname]
, [Status] = s.[Status]
, [Cmd] = s.[cmd]
, [Last Batch] = s.[last_batch]
, [Kill Command] = 'Kill ' + CAST(s.[spid] AS varchar(10))
, [Buffer Command] = 'DBCC InputBuffer(' + CAST(s.[spid] AS varchar(10))
+ ')'
FROM [master].[dbo].[sysprocesses] s WITH(NOLOCK)
JOIN [master].[sys].[databases] d WITH(NOLOCK)
ON s.[dbid] = d.[database_id]
WHERE s.[Status] 'background'
AND s.[spid] ##SPID --#CurrentSpid#
ORDER BY s.[blocked] DESC, s.[physical_io] DESC, s.[cpu] DESC, CONVERT([sysname], RTRIM(s.[Loginame]))
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT [Spid] = er.[session_Id]
, [ECID] = sp.[ECID]
, [Database] = DB_NAME(sp.[dbid])
, [User] = [nt_username]
, [Status] = er.[status]
, [Wait] = [wait_type]
, [Individual Query] = SUBSTRING(qt.[text], er.[statement_start_offset] / 2, (CASE WHEN er.[statement_end_offset] = - 1 THEN LEN(CONVERT(VARCHAR(MAX), qt.[text])) * 2
ELSE er.[statement_end_offset] END - er.[statement_start_offset]) / 2)
, [Parent Query] = qt.[text]
, [Program] = sp.[program_name]
, [Hostname] = sp.[Hostname]
, [Domain] = sp.[nt_domain]
, [Start_time] = er.[Start_time]
FROM [sys].[dm_exec_requests] er WITH(NOLOCK)
INNER JOIN [sys].[sysprocesses] sp WITH(NOLOCK)
ON er.[session_id] = sp.[spid]
CROSS APPLY [sys].[dm_exec_sql_text](er.[sql_handle]) qt
WHERE er.[session_Id] > 50 -- Ignore system spids.
AND er.[session_Id] NOT IN (##SPID) -- Ignore the current statement.
ORDER BY er.[session_Id], sp.[ECID]
END
GO

How do I query if a database schema exists

As part of our build process we run a database update script as we deploy code to 4 different environments. Further, since the same query will get added to until we drop a release into production it has to be able to run multiple times on a given database. Like this:
IF NOT EXISTS (SELECT * FROM sys.tables WHERE object_id = OBJECT_ID(N'[Table]'))
BEGIN
CREATE TABLE [Table]
(...)
END
Currently I have a create schema statement in the deployment/build script. Where do I query for the existence of a schema?
Are you looking for sys.schemas?
IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = 'jim')
BEGIN
EXEC('CREATE SCHEMA jim')
END
Note that the CREATE SCHEMA must be run in its own batch (per the answer below)
#bdukes is right on the money for determining if the schema exists, but the statement above won't work in SQL Server 2005. CREATE SCHEMA <name> needs to run in its own batch. A work around is to execute the CREATE SCHEMA statement in an exec.
Here is what I used in my build scripts:
IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = '<name>')
BEGIN
-- The schema must be run in its own batch!
EXEC( 'CREATE SCHEMA <name>' );
END
This is old so I feel compelled to add: For SQL SERVER 2008+ These all work (for the select part), then use EXECUTE('CREATE SCHEMA <name>') to actually create it on negative results.
DECLARE #schemaName sysname = 'myfunschema';
-- shortest
If EXISTS (SELECT 1 WHERE SCHEMA_ID(#schemaName) IS NOT NULL)
PRINT 'YEA'
ELSE
PRINT 'NOPE'
SELECT DB_NAME() AS dbname WHERE SCHEMA_ID(#schemaName) IS NOT NULL -- nothing returned if not there
IF NOT EXISTS ( SELECT top 1 *
FROM sys.schemas
WHERE name = #schemaName )
PRINT 'WOOPS MISSING'
ELSE
PRINT 'Has Schema'
SELECT SCHEMA_NAME(SCHEMA_ID(#schemaName)) AS SchemaName1 -- null if not there otherwise schema name returned
SELECT SCHEMA_ID(#schemaName) AS SchemaID1-- null if not there otherwise schema id returned
IF EXISTS (
SELECT sd.SchemaExists
FROM (
SELECT
CASE
WHEN SCHEMA_ID(#schemaName) IS NULL THEN 0
WHEN SCHEMA_ID(#schemaName) IS NOT NULL THEN 1
ELSE 0
END AS SchemaExists
) AS sd
WHERE sd.SchemaExists = 1
)
BEGIN
SELECT 'Got it';
END
ELSE
BEGIN
SELECT 'Schema Missing';
END
If the layout of components allows it, this works too.
IF EXISTS (SELECT 1 FROM sys.schemas WHERE name = 'myschema') SET NOEXEC ON
go
CREATE SCHEMA myschema
GO
SET NOEXEC OFF -- if any further processing is needed.
GO
Just to be extra "defensive", the following version generates a Type conversion error to account for the possibility (however unlikely) of > 1 matching Schema's similar to how validation code often intentionally Throw Exception's because I believe it's good to and I believe it's "'best practice'" to account for all possible return results however unlikely and even if it's just to generate a fatal exception because the known effects of stopping processing is usually better than unknown cascading effects of un-trapped errors. Because it's highly unlikely, I didn't think it's worth the trouble of a separate Count check + Throw or Try-Catch-Throw to generate a more user-friendly fatal error but still fatal error nonetheless.
SS 2005-:
declare #HasSchemaX bit
set #HasSchemaX = case (select count(1) from sys.schemas where lower(name) = lower('SchemaX')) when 1 then 1 when 0 then 0 else 'ERROR' end
SS 2008+:
declare #HasSchemaX bit = case (select count(1) from sys.schemas where lower(name) = lower('SchemaX')) when 1 then 1 when 0 then 0 else 'ERROR' end
Then:
if #HasSchemaX = 1
begin
...
end -- if #HasSchemaX = 1
IF NOT EXISTS (SELECT TOP (1) 1 FROM [sys].[schemas] WHERE [name] = 'Person')
BEGIN
EXEC ('CREATE SCHEMA [Person]')
END
IF NOT EXISTS (SELECT TOP (1) 1 FROM [sys].[tables] AS T
INNER JOIN [sys].[schemas] AS S ON S.schema_id = T.schema_id
WHERE T.[name] = 'Guests' AND S.[name] = 'Person')
BEGIN
EXEC ('CREATE TABLE [Person].[Guests]
(
[GuestId] INT IDENTITY(1, 1) NOT NULL,
[Forename] NVARCHAR(100) NOT NULL,
[Surname] NVARCHAR(100) NOT NULL,
[Email] VARCHAR(255) NOT NULL,
[BirthDate] DATETIME2 NULL,
CONSTRAINT [PK_Guests_GuestId] PRIMARY KEY CLUSTERED ([GuestId]),
CONSTRAINT [UX_Guests_Email] UNIQUE([Email])
)')
END
NOTICE: CREATE SCHEMA AND CREATE TABLE NEED COMPLETLY SEPARATED BATCH TO EXECUTE
TO MORE DESCRIPTION VISIT MICROSOFT DOCS WEBSITE :)
As of SQL Server 2005 version 9.0 you can use the INFORMATION_SCHEMA.SCHEMATA view to check if the schema exists:
IF NOT EXISTS (
SELECT SCHEMA_NAME
FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = '<schema name>' )
BEGIN
EXEC sp_executesql N'CREATE SCHEMA <schema name>'
END
GO
INFORMATION_SCHEMA views are the ISO standard and are generally preferable; these were adopted to make the syntax more consistent across different SQL database platforms.
Note that the CREATE SCHEMA must be run in its own batch