Determined having #Exclude_Query_Output = 0 is the failing piece in the SQL code. I have no idea on how to correct this.
I've been working on correcting this issue for quite (Months) a while when sending DB Mail from a SQL job. I created one SQL job executing a stored procedure that queries another servers database & tables. Then the results are stored in a variable and emailed to users daily.
Here is my setup:
Linked server A to linked server B using a SQL user named 'xxxdba'
Server type SQL Server in Linked Server Properties
On both servers I'm using "Be made using this security context"
The user has the database role "DatabaseMailUserRole"
Job owner is NT Service/SQLSERVERAGENT
The job is ran as xxxdba in the job step advanced area
On both servers A & B the user has read/write user mappings to the tables in the query which I have supplied below. Under the database itself, the user has execute to the stored procedure that I created.
Job step properties:
Step name
Type T-SQL
Run As (Blank)
Database (Win)
Command: Execute dbo.procedure_db_mail
Procedure that was created:
CREATE PROCEDURE PROCEDURE_DB_MAIL
AS
Declare #Qry varchar(5000) = 'EXEC XXXXXX.WIN.DBO.[Table_Roll_View]' --VIEW
SET #Qry = N'SELECT [Previous Day Table Roll Information] --Stored Procedure
From MSDB.DBO.sysjobs'
EXEC msdb.dbo.sp_send_dbmail
#recipients = 'Jwendt#xxxxxxx.com;',
#Query = #Qry,
#query_result_header = 1,
#exclude_query_output = 0,
#execute_query_database = 'Win',
#subject = 'Table Roll Data',
#attach_query_result_as_file = 1,
#query_attachment_filename = 'Table Roll Data.txt',
#append_query_error = 1,
#profile_name = 'SQL Mail Alert'
View Information:
CREATE VIEW Table_Roll_View
AS
SELECT DISTINCT a.Timestamp, a.DocGamingDate,
a.Document_ID, a.DocType,
t1.InternalStatus, a.DocStatus, a.DocNumber, b.Name, t1.Description, T1.XXXXGameName, b.Location_ID, T1.PitID, T1.TableID
From OPENQUERY([XXXXITDB], 'Select DISTINCT b.PitID, b.TableID, b.Description, a.GameCode, b.XXXXGameName, b.XXXXTableName, b.InternalStatus,
b.ExternalGameDay, b.InternalGameDay
From [XXXXIT].[dbo].[CurrentTableConfig] a
INNER JOIN [XXXXIT].[dbo].[Tables] b
on a.SAKEY = b.TableSAKEY'
) t1
INNER JOIN [Win].[dbo].[XX_Location] b
on b.Name = t1.XXXXTableName
INNER JOIN [Win].[dbo].[XX_Document] a
ON a.Location_ID = b.location_ID
Where a.DocGamingDate = CAST(GETDATE() -1 AS Date) --Looking at yesterday's table processes
--OR a.DocGamingDate = GETDATE() --Including today's table openers
and t1.description NOT LIKE '%zz%'
Execute the job (I'm a sys admin on all servers)
SQL History Message:
Executed as user: xxxdba. Failed to initialize sqlcmd library with error number -2147467259. [SQLSTATE 42000] (Error 22050). The step failed.
Windows Application Log:
SQL Server Scheduled Job 'Previous Day Table Roll Information' (0x74F50053DC25DD439C6438B586359845) - Status: Failed - Invoked on: 2021-02-24 10:19:46 - Message: The job failed. The Job was invoked by User XXXXXXXXXXX\jwendt. The last step to run was step 1 (Execute and email).
Additional notes:
I made the linked server credential a system admin for testing purposes and got the same error.
I get the same result if I execute the SP by itself outside of the job
If I run as myself, the results are the same.
Shared Memory, Named Pipes and TCP/IP are enabled on both servers
Data Access, RPC, RPC Out, Use Remote Collation and Enable Promotion of Distributed Transaction is set to True in the linked server properties
I have the same issue on another server and here is where it gets VERY confusing. I have the same setup and permissions for the user above. The difference is, I have an email that goes out preload and post load.
Management gets an email for a point multiplier that customers earn playing Bingo on Sunday's. This email works correctly (Preload). Once the post load time has passed, the email fails. If the local server time is 10AM then management would already have received their email at 7AM. If the post load time is set to 11AM and the local server time >= 11AM the job fails with the SQLCMD Library error.
I am running SQL Server Agent Jobs in SQL Server 2014, It has "Always On" enabled.
Primary server: A
Secondary Server: B
We faced a situation, Server A had a network issue so "Always on" feature automatically switched the primary server to B.
In this case, our jobs are running in Server A so it has been failed since the Server A goes to read only mode.
Is there a way to automate the SQL Server Agent Jobs without any manual intervention using "Always on"
You could have the jobs on both instances, your primary and secondary replica and then use sys.fn_hadr_is_primary_replica in the first step of your job.
IF sys.fn_hadr_is_primary_replica ( 'yourDBname' ) <> 1
BEGIN
-- raiserror, so the job step fails and the entire job fails
-- sometimes you may want to set this job to "finish with success" when this step fails
-- so that you don't get alerts
declare #errMsg varchar(600) = 'This is meant to run on the primary replica'
raiserror(#errMsg,16,1)
END
ELSE
BEGIN
print 'This is the primary replica, continue with the job'
END
That would work for 2014+. For 2012 you can check some sys views for the first step.
IF EXISTS(SELECT
AGC.name -- Availability Group
, RCS.replica_server_name -- SQL cluster node name
, ARS.role_desc -- Replica Role
, AGL.dns_name -- Listener Name
FROM
sys.availability_groups_cluster AS AGC
LEFT JOIN sys.dm_hadr_availability_replica_cluster_states AS RCS
ON RCS.group_id = AGC.group_id
LEFT JOIN sys.dm_hadr_availability_replica_states AS ARS
ON ARS.replica_id = RCS.replica_id
LEFT JOIN sys.availability_group_listeners AS AGL
ON AGL.group_id = ARS.group_id
WHERE
RCS.replica_server_name = ##SERVERNAME
and ARS.role_desc = 'PRIMARY')
BEGIN
print 'Continue with job'
END
ELSE
BEGIN
declare #errMsg varchar(600) = 'This is meant to run on the primary replica'
raiserror(#errMsg,16,1)
END
I am using web application to insert, update and delete records in a SQL Server table. The audit for this table is captured in another table when any insert, update, delete happens from GUI.
The insert, update is capturing the username correctly but the delete from GUi capture the SQL account not the web username, who deleted the records.
Please suggest a solution.
The trigger code for delete is as below:
-- DELETE
if exists (select 1 from deleted) and not exists (select 1 from inserted)
BEGIN
DECLARE #id varbinary(85)
DECLARE #who varchar(50)
SELECT #id = [Transaction SID]
FROM fn_dblog(NULL, NULL)
WHERE [Operation] = 'LOP_BEGIN_XACT'
AND [Transaction ID] = (SELECT TOP 1 [Transaction ID]
FROM fn_dblog(NULL, NULL)
WHERE Operation = 'LOP_DELETE_ROWS'
AND AllocUnitName like 'dbo.sampletable%'
ORDER BY [Transaction ID] DESC)
SET #who = SUSER_SNAME(#id)
INSERT sampletableAudit
SELECT
'D' as Operation, Id, Type, #who, getdate()
FROM
deleted
END
On an active machine this query takes forever. Who knows what happens to this query if, and when, the transaction log is backed up. On my machine (which has a busy database) this has been running for 7 minutes with no results so I stopped it.
If you are running SQL Server 2008 and on you can get the same results using SQL Server Audit (with much, much less of an impact). Otherwise why can't you just use user_name?
I have a SQL table that all of a sudden cannot return data unless I include with (nolock) on the end, which indicates some kind of lock left on my table.
I've experimented a bit with sys.dm_tran_locks to identify that there are in fact a number of locks on the table, but how do I identify what is locking them (ie the request element of the sys.dm_tran_locks)?
EDIT: I know about sp_lock for pre SQL 2005, but now that that sp is deprecated, AFAIK the right way to do this is with sys.dm_tran_locks. I'm using SQL Server 2008 R2.
Take a look at the following system stored procedures, which you can run in SQLServer Management Studio (SSMS):
sp_who
sp_lock
Also, in SSMS, you can view locks and processes in different ways:
Different versions of SSMS put the activity monitor in different places. For example, SSMS 2008 and 2012 have it in the context menu when you right-click on a server node.
For getting straight to "who is blocked/blocking" I combined/abbreviated sp_who and sp_lock into a single query which gives a nice overview of who has what object locked to what level.
--Create Procedure WhoLock
--AS
set nocount on
if object_id('tempdb..#locksummary') is not null Drop table #locksummary
if object_id('tempdb..#lock') is not null Drop table #lock
create table #lock ( spid int, dbid int, objId int, indId int, Type char(4), resource nchar(32), Mode char(8), status char(6))
Insert into #lock exec sp_lock
if object_id('tempdb..#who') is not null Drop table #who
create table #who ( spid int, ecid int, status char(30),
loginame char(128), hostname char(128),
blk char(5), dbname char(128), cmd char(16)
--
, request_id INT --Needed for SQL 2008 onwards
--
)
Insert into #who exec sp_who
Print '-----------------------------------------'
Print 'Lock Summary for ' + ##servername + ' (excluding tempdb):'
Print '-----------------------------------------' + Char(10)
Select left(loginame, 28) as loginame,
left(db_name(dbid),128) as DB,
left(object_name(objID),30) as object,
max(mode) as [ToLevel],
Count(*) as [How Many],
Max(Case When mode= 'X' Then cmd Else null End) as [Xclusive lock for command],
l.spid, hostname
into #LockSummary
from #lock l join #who w on l.spid= w.spid
where dbID != db_id('tempdb') and l.status='GRANT'
group by dbID, objID, l.spid, hostname, loginame
Select * from #LockSummary order by [ToLevel] Desc, [How Many] Desc, loginame, DB, object
Print '--------'
Print 'Who is blocking:'
Print '--------' + char(10)
SELECT p.spid
,convert(char(12), d.name) db_name
, program_name
, p.loginame
, convert(char(12), hostname) hostname
, cmd
, p.status
, p.blocked
, login_time
, last_batch
, p.spid
FROM master..sysprocesses p
JOIN master..sysdatabases d ON p.dbid = d.dbid
WHERE EXISTS ( SELECT 1
FROM master..sysprocesses p2
WHERE p2.blocked = p.spid )
Print '--------'
Print 'Details:'
Print '--------' + char(10)
Select left(loginame, 30) as loginame, l.spid,
left(db_name(dbid),15) as DB,
left(object_name(objID),40) as object,
mode ,
blk,
l.status
from #lock l join #who w on l.spid= w.spid
where dbID != db_id('tempdb') and blk <>0
Order by mode desc, blk, loginame, dbID, objID, l.status
(For what the lock level abbreviations mean, see e.g. https://technet.microsoft.com/en-us/library/ms175519%28v=sql.105%29.aspx)
Copied from: sp_WhoLock – a T-SQL stored proc combining sp_who and sp_lock...
NB the [Xclusive lock for command] column can be misleading -- it shows the current command for that spid; but the X lock could have been triggered by an earlier command in the transaction.
exec sp_lock
This query should give you existing locks.
exec sp_who SPID -- will give you some info
Having spids, you could check activity monitor(processes tab) to find out what processes are locking the tables ("details" for more info and "kill process" to kill it).
I have a stored procedure that I have put together, that deals not only with locks and blocking, but also to see what is running in a server.
I have put it in master.
I will share it with you, the code is below:
USE [master]
go
CREATE PROCEDURE [dbo].[sp_radhe]
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
-- the current_processes
-- marcelo miorelli
-- CCHQ
-- 04 MAR 2013 Wednesday
SELECT es.session_id AS session_id
,COALESCE(es.original_login_name, '') AS login_name
,COALESCE(es.host_name,'') AS hostname
,COALESCE(es.last_request_end_time,es.last_request_start_time) AS last_batch
,es.status
,COALESCE(er.blocking_session_id,0) AS blocked_by
,COALESCE(er.wait_type,'MISCELLANEOUS') AS waittype
,COALESCE(er.wait_time,0) AS waittime
,COALESCE(er.last_wait_type,'MISCELLANEOUS') AS lastwaittype
,COALESCE(er.wait_resource,'') AS waitresource
,coalesce(db_name(er.database_id),'No Info') as dbid
,COALESCE(er.command,'AWAITING COMMAND') AS cmd
,sql_text=st.text
,transaction_isolation =
CASE es.transaction_isolation_level
WHEN 0 THEN 'Unspecified'
WHEN 1 THEN 'Read Uncommitted'
WHEN 2 THEN 'Read Committed'
WHEN 3 THEN 'Repeatable'
WHEN 4 THEN 'Serializable'
WHEN 5 THEN 'Snapshot'
END
,COALESCE(es.cpu_time,0)
+ COALESCE(er.cpu_time,0) AS cpu
,COALESCE(es.reads,0)
+ COALESCE(es.writes,0)
+ COALESCE(er.reads,0)
+ COALESCE(er.writes,0) AS physical_io
,COALESCE(er.open_transaction_count,-1) AS open_tran
,COALESCE(es.program_name,'') AS program_name
,es.login_time
FROM sys.dm_exec_sessions es
LEFT OUTER JOIN sys.dm_exec_connections ec ON es.session_id = ec.session_id
LEFT OUTER JOIN sys.dm_exec_requests er ON es.session_id = er.session_id
LEFT OUTER JOIN sys.server_principals sp ON es.security_id = sp.sid
LEFT OUTER JOIN sys.dm_os_tasks ota ON es.session_id = ota.session_id
LEFT OUTER JOIN sys.dm_os_threads oth ON ota.worker_address = oth.worker_address
CROSS APPLY sys.dm_exec_sql_text(er.sql_handle) AS st
where es.is_user_process = 1
and es.session_id <> ##spid
and es.status = 'running'
ORDER BY es.session_id
end
GO
this procedure has done very good for me in the last couple of years.
to run it just type sp_radhe
Regarding putting sp_radhe in the master database
I use the following code and make it a system stored procedure
exec sys.sp_MS_marksystemobject 'sp_radhe'
as you can see on the link below
Creating Your Own SQL Server System Stored Procedures
Regarding the transaction isolation level
Questions About T-SQL Transaction Isolation Levels You Were Too Shy to Ask
Jonathan Kehayias
Once you change the transaction isolation level it only changes when
the scope exits at the end of the procedure or a return call, or if
you change it explicitly again using SET TRANSACTION ISOLATION LEVEL.
In addition the TRANSACTION ISOLATION LEVEL is only scoped to the
stored procedure, so you can have multiple nested stored procedures
that execute at their own specific isolation levels.
This should give you all the details of the existing locks.
DECLARE #tblVariable TABLE(SPID INT, Status VARCHAR(200), [Login] VARCHAR(200), HostName VARCHAR(200),
BlkBy VARCHAR(200), DBName VARCHAR(200), Command VARCHAR(200), CPUTime INT,
DiskIO INT, LastBatch VARCHAR(200), ProgramName VARCHAR(200), _SPID INT,
RequestID INT)
INSERT INTO #tblVariable
EXEC Master.dbo.sp_who2
SELECT v.*, t.TEXT
FROM #tblVariable v
INNER JOIN sys.sysprocesses sp ON sp.spid = v.SPID
CROSS APPLY sys.dm_exec_sql_text(sp.sql_handle) AS t
ORDER BY BlkBy DESC, CPUTime DESC
You can then kill, with caution, the SPID that blocks your table.
kill 104 -- Your SPID
You can also use sp_who2 which gives more information
Here is some info http://dbadiaries.com/using-sp_who2-to-help-with-sql-server-troubleshooting
As per the official docs the sp_lock is mark as deprecated:
This feature is in maintenance mode and may be removed in a future
version of Microsoft SQL Server. Avoid using this feature in new
development work, and plan to modify applications that currently use
this feature.
and it is recommended to use sys.dm_tran_locks instead. This dynamic management object returns information about currently active lock manager resources. Each row represents a currently active request to the lock manager for a lock that has been granted or is waiting to be granted.
It generally returns more details in more user friendly syntax then sp_lock does.
The whoisactive routine written by Adam Machanic is very good to check the current activity in your environment and see what types of waits/locks are slowing your queries. You can very easily find what is blocking your queries and tons of other handy information.
For example, let's say we have the following queries running in the default SQL Server Isolation Level - Read Committed. Each query is executing in separate query window:
-- creating sample data
CREATE TABLE [dbo].[DataSource]
(
[RowID] INT PRIMARY KEY
,[RowValue] VARCHAR(12)
);
INSERT INTO [dbo].[DataSource]([RowID], [RowValue])
VALUES (1, 'samle data');
-- query window 1
BEGIN TRANSACTION;
UPDATE [dbo].[DataSource]
SET [RowValue] = 'new data'
WHERE [RowID] = 1;
--COMMIT TRANSACTION;
-- query window 2
SELECT *
FROM [dbo].[DataSource];
Then execute the sp_whoisactive (only part of the columns are displayed):
You can easily seen the session which is blocking the SELECT statement and even its T-SQL code. The routine has a lot of parameters, so you can check the docs for more details.
If we query the sys.dm_tran_locks view we can see that one of the session is waiting for a share lock of a resource, that has exclusive lock by other session:
Plot twist!
You can have orphaned distributed transactions holding exclusive locks and you will not see them if your script assumes there is a session associated with the transaction (there isn't!). Run the script below to identify these transactions:
;WITH ORPHANED_TRAN AS (
SELECT
dat.name,
dat.transaction_uow,
ddt.database_transaction_begin_time,
ddt.database_transaction_log_bytes_reserved,
ddt.database_transaction_log_bytes_used
FROM
sys.dm_tran_database_transactions ddt,
sys.dm_tran_active_transactions dat,
sys.dm_tran_locks dtl
WHERE
ddt.transaction_id = dat.transaction_id AND
dat.transaction_id = dtl.request_owner_id AND
dtl.request_session_id = -2 AND
dtl.request_mode = 'X'
)
SELECT DISTINCT * FROM ORPHANED_TRAN
Once you have identified the transaction, use the transaction_uow column to find it in MSDTC and decide whether to abort or commit it. If the transaction is marked as In Doubt (with a question mark next to it) you will probably want to abort it.
You can also kill the Unit Of Work (UOW) by specifying the transaction_uow in the KILL command:
KILL '<transaction_uow>'
References:
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/kill-transact-sql?view=sql-server-2017#arguments
https://www.mssqltips.com/sqlservertip/4142/how-to-kill-a-blocking-negative-spid-in-sql-server/
A colleague and I have created a tool just for this.
It's a visual representation of all the locks that your sessions produce.
Give it a try (http://www.sqllockfinder.com), it's open source (https://github.com/LucBos/SqlLockFinder)