Related
I'm trying to send attached file from query result using sp_send_dbmail
This is my code:
declare #q nvarchar(max)
select #q = 'select
case when s.mantype = ''99'' then ''Pre-sales''
when s.mantype = ''44'' then ''idk''
when s.mantype = ''77'' then ''Van sales''
when s.mantype = ''33'' then ''Delivery Person''
when s.mantype = ''55'' then ''Manager''
end ''mantype''
from man s '
begin
select #sub = 'Fire a Test ' + cast(convert(date,getdate()) as nvarchar)
EXEC msdb.dbo.sp_send_dbmail
#recipients = 'my#email.com',
#profile_name = 'Profileone',
#subject = #sub,
#body ='TEST' ,
#body_format = 'TEXT',
#query_result_header = 1 ,
#query = #q,
#attach_query_result_as_file = 1,
#query_attachment_filename= 'Report.cvs';
end
but I'm getting an error :
Failed to initialize sqlcmd library with error number -2147467259
Note: when I remove the case in the query and select the column mantype, it runs, but when I add the case again, I get the above error.
It's been a while, I solved this issue by creating a view with the desired query.
Failed to initialize sqlcmd library with error number -2147467259. When I remove the count and group by the query works perfectly. I add the count and group by I get the error above.
'''
DECLARE #sub VARCHAR(100);
DECLARE #qry VARCHAR(1000);
DECLARE #msg VARCHAR(250);
DECLARE #query_ath NVARCHAR(1000);
DECLARE #query_attachment_filename NVARCHAR(1000);
DECLARE #tab char(1) = CHAR(9);
SELECT #sub = 'Daily Absence Report';
SELECT #msg = 'Please refer to the attached spread sheet for the report.'
SELECT #query_ath = 'select a.SCS_STUDENT,
concat(d.FIRST_NAME,'' '',d.LAST_NAME) as Student_Name,
c.STA_OTHER_COHORT_GROUPS,
b.STC_COURSE_NAME,
b.STUDENT_ACAD_CRED_ID,
e.SCS_ABSENT_DATES,
count(case e.SCS_ATTENDANCE_TYPES when ''A'' then 1 end) as
Number_of_Absences
from STUDENT_COURSE_SEC a, STUDENT_ACAD_CRED b, STA_OTHER_COHORTS c, PERSON
d, SCS_ATTENDANCE e
where a.SCS_STUDENT_ACAD_CRED = b.STUDENT_ACAD_CRED_ID
and b.STC_REPORTING_TERM = ''2019FA''
and b.STC_PERSON_ID = left(c.STUDENT_ACAD_LEVELS_ID, 7)
and b.STC_PERSON_ID = d.ID
and c.STA_OTHER_COHORT_GROUPS like ''AT%''
and c.STA_OTHER_COHORT_GROUPS <> ''ATCHR''
and a.STUDENT_COURSE_SEC_ID = e.STUDENT_COURSE_SEC_ID
and e.SCS_ATTENDANCE_TYPES = ''A''
and CONVERT(date, getdate()) = e.SCS_ABSENT_DATES
group by a.SCS_STUDENT,
concat(d.FIRST_NAME,'' '',d.LAST_NAME),
c.STA_OTHER_COHORT_GROUPS,
b.STC_COURSE_NAME,
b.STUDENT_ACAD_CRED_ID,
e.SCS_ABSENT_DATES';
SELECT #query_attachment_filename = 'ath_absences.csv';
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'elearning no shows',
#recipients = 'email', --'ajenkins#eastms.edu',
#copy_recipients = 'rboles#eastms.edu',
#body = #msg,
#subject = #sub,
#execute_query_database = 'db_server',
#query = #query_ath,
#query_attachment_filename = 'ath_absences.csv',
#attach_query_result_as_file = 1,
#query_result_header = 1,
#query_result_width = 256,
#query_result_separator=#tab,
#query_result_no_padding = 1;
'''
As per our discussion in the comments, please increase the number of characters for #query_ath.
I'm trying to follow the link in order to send automated emails with the descriptions of the job failures.
However, when I'm trying to pass these arguments into the procedure:
EXEC msdb.dbo.TestMail
#job_id = '$(ESCAPE_SQUOTE(JOBID))'
,#strtdt = '$(ESCAPE_SQUOTE(STRTDT))'
,#strttm = '$(ESCAPE_SQUOTE(STRTTM))'
,#operator_name = 'MSXOperator'
,#mail_on_success = 'Y'
,#attach_output_file = 'ON_FAILUR
I see the following error:
Msg 8114, Level 16, State 5, Procedure TestMail, Line 0
Error converting data type varchar to uniqueidentifier.
The code for TestMail is
USE msdb
GO
IF OBJECT_ID('dbo.TestMail') IS NOT NULL DROP PROC dbo.TestMail
GO
CREATE PROC dbo.TestMail
#job_id uniqueidentifier
,#strtdt varchar(100)
,#strttm varchar(100)
,#operator_name sysname = 'MSXOperator'
,#mail_on_success char(1) = 'Y' --'Y', 'N'
,#attach_output_file varchar(10) = 'ON_FAILURE' --'ALWAYS', 'NEVER', 'ON_FAILURE'
AS
SET NOCOUNT ON
DECLARE
#job_name sysname
,#job_id_str varchar(200) --GUID representation as string without hyphens
,#email_address nvarchar(300)
,#run_status int --0 = Failed, 1 = Succeeded, 2 = Retry, 3 = Canceled
,#run_status_desc varchar(9) --Failed, Succeeded, Retry, Canceled
,#importance varchar(6) --low, normal, high
,#output_file_names varchar(max)
,#subject nvarchar(255)
,#body nvarchar(max)
,#step_name sysname --to hold name of jobstep
,#step_duration int
,#step_duration_str varchar(20)
,#job_duration int
,#job_duration_str varchar(20)
,#step_id int
,#step_run_status int
,#step_run_status_desc varchar(9)
,#crlf char(2)
,#send_mail_bit bit --calculated just before send mail routine
,#attach_output_file_bit bit --calculated just before send mail routine
,#ag_tkn_step_id varbinary(200)
,#ag_tkn_job_id varbinary(200)
,#ag_tkn_strt_dt varbinary(200)
,#ag_tkn_strt_tm varbinary(200)
,#ag_tkn_mach_nm varbinary(200)
,#ag_tkn_inst_nm varbinary(200)
SET #crlf = CHAR(13) + CHAR(10)
SET #body = ''
------------------------------------------------------------------------------------------------------------------------------
--We can't represent agent tokens as strings if we want to push this proc out from an MSX server.
--The first SELECT is only used in dev, to ger each strin representation as varbinary.
-- This will look weird when deployed on a TSX server.
--The second part sets each variable to a varbinary representation of each string.
--The variable are used later in the proc
------------------------------------------------------------------------------------------------------------------------------
--SELECT
-- CAST('$(ESCAPE_SQUOTE(STEPID))' AS varbinary(200))
--,CAST('$(ESCAPE_SQUOTE(JOBID))' AS varbinary(200))
--,CAST('$(ESCAPE_SQUOTE(STRTDT))' AS varbinary(200))
--,CAST('$(ESCAPE_SQUOTE(STRTTM))' AS varbinary(200))
--,CAST('$(ESCAPE_SQUOTE(MACH))' AS varbinary(200))
--,CAST('$(ESCAPE_SQUOTE(INST))' AS varbinary(200))
SET #ag_tkn_step_id = 0x24284553434150455F5351554F5445285354455049442929
SET #ag_tkn_job_id = 0x24284553434150455F5351554F5445284A4F4249442929
SET #ag_tkn_strt_dt = 0x24284553434150455F5351554F5445285354525444542929
SET #ag_tkn_strt_tm = 0x24284553434150455F5351554F54452853545254544D2929
SET #ag_tkn_mach_nm = 0x24284553434150455F5351554F5445284D4143482929
SET #ag_tkn_inst_nm = 0x24284553434150455F5351554F544528494E53542929
------------------------------------------------------------------------------------------------------------------------------
--Validate input parameters
-------------------------------------------------------------------------------------------------------------------------------
IF #mail_on_success NOT IN('Y', 'N')
BEGIN
RAISERROR('Bad value for parameter #mail_on_success, values allowed are ''Y'' and ''N''.', 16, 1)
RETURN
END
IF #attach_output_file NOT IN ('ALWAYS', 'NEVER', 'ON_FAILURE')
BEGIN
RAISERROR('Bad value for parameter #attach_output_file, values allowed are ''ALWAYS'', ''NEVER'' andd ''ON_FAILURE''.', 16, 1)
RETURN
END
-------------------------------------------------------------------------------------------------------------------------------
--Get job name
------------------------------------------------------------------------------------------------------------------------------
SET #job_name = (SELECT s.name FROM msdb.dbo.sysjobs AS s WHERE s.job_id = #job_id)
IF #job_name IS NULL
BEGIN
RAISERROR('Failed to retreive job name baed on #job_id, teminating procedure MailAfterJob.', 16, 1)
RETURN
END
------------------------------------------------------------------------------------------------------------------------------
--String representation of job_id (to match representation in file name)
------------------------------------------------------------------------------------------------------------------------------
SET #job_id_str = UPPER(master.dbo.fn_varbintohexstr(#job_id))
------------------------------------------------------------------------------------------------------------------------------
--Get email_address for operator
-------------------------------------------------------------------------------------------------------------------------------
SET #email_address = (SELECT o.email_address FROM msdb.dbo.sysoperators AS o WHERE o.name = #operator_name)
IF #email_address IS NULL
BEGIN
RAISERROR('Unknown mail operator name, teminating procedure MailAfterJob.', 16, 1)
RETURN
END
------------------------------------------------------------------------------------------------------------------------------
--Get job outcome for *this* execuution, store in table variable
------------------------------------------------------------------------------------------------------------------------------
DECLARE #jobhistory table(instance_id int, step_id int, run_status int, step_name sysname, step_duration int)
INSERT INTO #jobhistory (instance_id, step_id, run_status, step_name, step_duration)
SELECT instance_id, step_id, run_status, step_name, run_duration
FROM msdb.dbo.sysjobhistory AS h
WHERE h.job_id = #job_id
AND msdb.dbo.agent_datetime(h.run_date, h.run_time) >= msdb.dbo.agent_datetime(CAST(#strtdt AS int), CAST(#strttm AS int))
------------------------------------------------------------------------------------------------------------------------------
--Get lowest run status for this execution (0 = fail)
------------------------------------------------------------------------------------------------------------------------------
SET #run_status = (SELECT MIN(h.run_status)
FROM #jobhistory AS h
INNER JOIN msdb.dbo.sysjobhistory AS hi ON hi.instance_id = h.instance_id
WHERE hi.job_id = #job_id)
IF #run_status IS NULL
BEGIN
RAISERROR('Could not determine run status for job, teminating procedure MailAfterJob.', 16, 1)
RETURN
END
SET #run_status_desc = CASE #run_status
WHEN 0 THEN 'FAILED'
WHEN 1 THEN 'SUCCEEDED'
WHEN 2 THEN 'RETRY'
WHEN 3 THEN 'CANCELED'
END
------------------------------------------------------------------------------------------------------------------------------
--Set importance for email
------------------------------------------------------------------------------------------------------------------------------
IF #run_status = 0
SET #importance = 'high'
ELSE
SET #importance = 'low'
------------------------------------------------------------------------------------------------------------------------------
--Get output file names to attach to email, in table variable
------------------------------------------------------------------------------------------------------------------------------
DECLARE #output_file_names_table table(output_file_name_step varchar(300))
INSERT INTO #output_file_names_table(output_file_name_step)
SELECT REPLACE(COALESCE(s.output_file_name, ''), CAST(#ag_tkn_step_id AS varchar(200)), CAST(s.step_id AS varchar(20))) AS out_file_name
FROM msdb.dbo.sysjobsteps AS s
WHERE s.job_id = #job_id
AND s.output_file_name IS NOT NULL
AND EXISTS(SELECT * FROM #jobhistory AS h WHERE h.step_id = s.step_id)
--Replace agent tokens with actual values
UPDATE #output_file_names_table SET output_file_name_step = REPLACE(output_file_name_step, CAST(#ag_tkn_job_id AS varchar(200)), #job_id_str)
UPDATE #output_file_names_table SET output_file_name_step = REPLACE(output_file_name_step, CAST(#ag_tkn_strt_dt AS varchar(200)), #strtdt)
UPDATE #output_file_names_table SET output_file_name_step = REPLACE(output_file_name_step, CAST(#ag_tkn_strt_tm AS varchar(200)), #strttm)
UPDATE #output_file_names_table SET output_file_name_step = REPLACE(output_file_name_step, CAST(#ag_tkn_mach_nm AS varchar(200)), CAST(SERVERPROPERTY('MachineName') AS varchar(100)))
UPDATE #output_file_names_table SET output_file_name_step = REPLACE(output_file_name_step, CAST(#ag_tkn_inst_nm AS varchar(200)), (ISNULL(CAST(SERVERPROPERTY('InstanceName') AS varchar(100)), '')))
--Loop table with file names, create semi-colon separated string
DECLARE #output_file_name_step varchar(300)
SET #output_file_names = ''
DECLARE c CURSOR FOR SELECT DISTINCT output_file_name_step FROM #output_file_names_table
OPEN c
WHILE 1 = 1
BEGIN
FETCH NEXT FROM c INTO #output_file_name_step
IF ##FETCH_STATUS <> 0
BREAK
SET #output_file_names = #output_file_names + #output_file_name_step + ';'
END
CLOSE c
DEALLOCATE c
--Remove the last semi-colon
IF LEN(#output_file_names) > 0
SET #output_file_names = SUBSTRING(#output_file_names, 1, LEN(#output_file_names) - 1)
------------------------------------------------------------------------------------------------------------------------------
--Construct email parts
------------------------------------------------------------------------------------------------------------------------------
--Set mail subject
--SET #subject = ##SERVERNAME + ' ' + #run_status_desc + ' ' + #job_name
SET #subject = CASE WHEN #run_status_desc = 'SUCCEEDED' THEN 'Ok' ELSE #run_status_desc END + ': ' + #job_name
--Set mail body
DECLARE c cursor FOR SELECT h.step_id, h.step_name, h.step_duration, h.run_status FROM #jobhistory AS h ORDER BY instance_id
OPEN c
WHILE 1 = 1
BEGIN
FETCH NEXT FROM c INTO #step_id, #step_name, #step_duration, #step_run_status
IF ##FETCH_STATUS <> 0
BREAK
SET #step_duration_str = RIGHT('00000' + CAST(#step_duration AS varchar(6)), 6) --Make sure we have 0:s first
SET #step_duration_str = SUBSTRING(#step_duration_str, 1, 2) + ':' +
SUBSTRING(#step_duration_str, 3, 2) + ':' + SUBSTRING(#step_duration_str, 5, 2)
SET #step_run_status_desc = CASE #step_run_status
WHEN 0 THEN 'FAILED'
WHEN 1 THEN 'SUCCEEDED'
WHEN 2 THEN 'RETRY'
WHEN 3 THEN 'CANCELED'
END
IF #step_id <> 0
SET #body = #body + 'Step "' + #step_name + '" executed ' + #step_run_status_desc + ', time ' + #step_duration_str + '.' + #crlf
END
CLOSE c
DEALLOCATE c
SET #job_duration = (SELECT SUM(step_duration) FROM #jobhistory)
SET #job_duration_str = RIGHT('00000' + CAST(#job_duration AS varchar(6)), 6) --Make sure we have 0:s first
SET #job_duration_str = SUBSTRING(#job_duration_str, 1, 2) + ':' +
SUBSTRING(#job_duration_str, 3, 2) + ':' + SUBSTRING(#job_duration_str, 5, 2)
SET #body = 'Job executed, time ' + #job_duration_str + '.' + #crlf + #crlf + #body
------------------------------------------------------------------------------------------------------------------------------
--Decide whether to send email
------------------------------------------------------------------------------------------------------------------------------
IF (#mail_on_success = 'N' AND #run_status = 1) --1 = Success
SET #send_mail_bit = 0
ELSE
SET #send_mail_bit = 1
------------------------------------------------------------------------------------------------------------------------------
--Decide whether to attach output file
------------------------------------------------------------------------------------------------------------------------------
SET #attach_output_file_bit = 0
IF #attach_output_file = 'ALWAYS'
SET #attach_output_file_bit = 1
IF #attach_output_file = 'NEVER'
SET #attach_output_file_bit = 0
IF #attach_output_file = 'ON_FAILURE' AND #run_status <> 1 --1 = Success
SET #attach_output_file_bit = 1
------------------------------------------------------------------------------------------------------------------------------
--Send the email
------------------------------------------------------------------------------------------------------------------------------
IF #send_mail_bit = 1
BEGIN
IF #attach_output_file_bit = 0
EXEC msdb.dbo.sp_send_dbmail --Do no attach output file
#recipients = #email_address
,#subject = #subject
,#body = #body
,#importance = #importance
ELSE
EXEC msdb.dbo.sp_send_dbmail --Do attach output file
#recipients = #email_address
,#subject = #subject
,#body = #body
,#importance = #importance
,#file_attachments = #output_file_names
END
------------------------------------------------------------------------------------------------------------------------------
--Exit with fail if we got here on failure
------------------------------------------------------------------------------------------------------------------------------
IF #run_status = 0
RAISERROR('Job failed', 16, 1)
------------------------------------------------------------------------------------------------------------------------------
/*
--Sample execution, as to be defined in job (this can look weird when deployed on TSX server)
EXEC sqlmaint.dbo.MailAfterJob
#job_id = $(ESCAPE_SQUOTE(JOBID))
,#strtdt = '$(ESCAPE_SQUOTE(STRTDT))'
,#strttm = '$(ESCAPE_SQUOTE(STRTTM))'
,#operator_name = 'MSXOperator'
,#mail_on_success = 'Y'
,#attach_output_file = 'ON_FAILURE' --'ALWAYS', 'NEVER', 'ON_FAILURE'
*/
------------------------------------------------------------------------------------------------------------------------------
GO
The link is: http://www.karaszi.com/sqlserver/util_MailAfterJob.asp
I was able to duplicate the error; it indicates the problem exactly. The problem is that you are quoting the token '$(ESCAPE_SQUOTE(JOBID))' causing the proc to think you are passing a string, implicitly converted to VARCHAR. Since VARCHAR doesn't implicitly convert to the defined UNIQUEIDENTIFIER, you get your error.
If you simply remove the quotes, in the job step, everything works as designed. Hopefully, you aren't trying to test this outside of a SQL Agent job or it will fail no matter what you do.
Simplified Proc to Address the conversion error:
use msdb
go
if OBJECT_ID('testString','P') is null
execute sp_executesql N'CREATE PROC testString as select ''stub'' stubProc'
go
alter proc testString
#job_id uniqueidentifier
as
declare #job_id_str varchar(200)
SET #job_id_str = UPPER( master.dbo.fn_varbintohexstr( #job_id ) )
select #job_id jobID, #job_id_str jobIDStr
Test job
USE [msdb]
GO
/****** Object: Job [id TEST] Script Date: 6/8/2016 9:06:06 AM ******/
EXEC msdb.dbo.sp_delete_job #job_name=N'id TEST', #delete_unused_schedule=1
GO
/****** Object: Job [id TEST] Script Date: 6/8/2016 9:06:06 AM ******/
BEGIN TRANSACTION
DECLARE #ReturnCode INT
SELECT #ReturnCode = 0
/****** Object: JobCategory [[Uncategorized (Local)]] Script Date: 6/8/2016 9:06:06 AM ******/
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1)
BEGIN
EXEC #ReturnCode = msdb.dbo.sp_add_category #class=N'JOB', #type=N'LOCAL', #name=N'[Uncategorized (Local)]'
IF (##ERROR <> 0 OR #ReturnCode <> 0) GOTO QuitWithRollback
END
DECLARE #jobId BINARY(16)
EXEC #ReturnCode = msdb.dbo.sp_add_job #job_name=N'id TEST',
#enabled=1,
#notify_level_eventlog=0,
#notify_level_email=0,
#notify_level_netsend=0,
#notify_level_page=0,
#delete_level=0,
#description=N'No description available.',
#category_name=N'[Uncategorized (Local)]',
#owner_login_name=N'DOMAIN\USER', #job_id = #jobId OUTPUT
IF (##ERROR <> 0 OR #ReturnCode <> 0) GOTO QuitWithRollback
/****** Object: Step [TEST] Script Date: 6/8/2016 9:06:06 AM ******/
EXEC #ReturnCode = msdb.dbo.sp_add_jobstep #job_id=#jobId, #step_name=N'TEST',
#step_id=1,
#cmdexec_success_code=0,
#on_success_action=1,
#on_success_step_id=0,
#on_fail_action=2,
#on_fail_step_id=0,
#retry_attempts=0,
#retry_interval=0,
#os_run_priority=0, #subsystem=N'TSQL',
#command=N'EXEC msdb.dbo.testString
#job_id = $(ESCAPE_SQUOTE(JOBID))',
#database_name=N'master',
#flags=0
IF (##ERROR <> 0 OR #ReturnCode <> 0) GOTO QuitWithRollback
EXEC #ReturnCode = msdb.dbo.sp_update_job #job_id = #jobId, #start_step_id = 1
IF (##ERROR <> 0 OR #ReturnCode <> 0) GOTO QuitWithRollback
EXEC #ReturnCode = msdb.dbo.sp_add_jobserver #job_id = #jobId, #server_name = N'(local)'
IF (##ERROR <> 0 OR #ReturnCode <> 0) GOTO QuitWithRollback
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
IF (##TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:
GO
Is there a way I can add the time in the following query as the body of my email :
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'TEST_DEV',
#recipients = 'xxx#gmail.com',
#query = ' select
Percentage = CONVERT(DECIMAL(10,1),100 - (CAST(COUNT(DISTINCT case when PD.Exception != ' ' then PD.Id END) as float)/CAST(COUNT(PD.Id) as float)*100))
from
DataBaseName.dbo.Product P INNER JOIN DataBaseName.dbo.LogProduct PD
ON P.LogId = PD.LogId
WHERE
ResponseTime < GETDATE() and RequestTime > DATEADD(MINUTE, -150, GETDATE())
' ,
#subject = 'Test',
#body = 'Please check the attached file for Providers with Many unsuccessful calls between the time xx an yy',
#attach_query_result_as_file = 1 ;
In the current line
#body = 'Please check the attached file for info on calls between the time xx an yy',
I would like to add GetDate() in place of xx and DATEADD(MINUTE, -150, GETDATE()) in place of yy ?
is it possible ?
declare #body nvarchar(max)
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'DEV',
#recipients = 'xxx#gmail.com',
#query = 'exec Database.dbo.spTest' ,
#subject = 'Test',
select #body = 'Please check the attached file for info on calls between the time ........................',
#attach_query_result_as_file = 1 ;
Would you want me to do something like this ?
You can declare your #body variable before the EXEC statement and make it any string that you'd like.
Edit:
I updated this to be more verbose. I dont have sp_send_dbmail configed anywhere to test, but I think it should work fine. I created a string variable called #bodyMsg, set it to the string you want before the stored procedure call, then gave the value over to the #body variable in sp_send_dbmail.
declare #bodyMsg nvarchar(max)
select #bodyMsg = 'Please check the attached file for info on calls between the time ' + convert(varchar,GETDATE()) + ' and ' + convert(varchar,DATEADD(mm, -150, getdate())) + '.'
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'TEST_DEV',
#recipients = 'xxx#gmail.com',
#query = ' select
Percentage = CONVERT(DECIMAL(10,1),100 - (CAST(COUNT(DISTINCT case when PD.Exception != ' ' then PD.Id END) as float)/CAST(COUNT(PD.Id) as float)*100))
from
DataBaseName.dbo.Product P INNER JOIN DataBaseName.dbo.LogProduct PD
ON P.LogId = PD.LogId
WHERE
ResponseTime < GETDATE() and RequestTime > DATEADD(MINUTE, -150, GETDATE())
' ,
#subject = 'Test',
#body = #bodyMsg,
#attach_query_result_as_file = 1 ;
Then just pass the #body variable to the sp_send_dbmail stored procedure. Different datetime formats can be found here: http://technet.microsoft.com/en-us/library/ms187928.aspx
I have created a wrapper stored procedure to create publication for transactional replication for SQL Server 2008 Standard Edition SP3. But when I execute the procedure I get the following error. The column "file_exists" is not user defined. This error doesn't make any sense to me. This works on Dev environment but same code doesn't work on test environment. Dev and Test are identical as far as I can tell. I also tried to explicitly set options, made them 5496 (SELECT ##OPTIONS). Any help greatly appreciated.
-- error
Msg 50000, Level 16, State 1, Procedure CreatePublicationForDB, Line 161
Invalid column name 'file_exists'.
-- Begin Script
CREATE DATABASE TestPublication
GO
USE TestPublication
CREATE TABLE Orders(
OrderID INT PRIMARY KEY,
CustomerID INT,
ProductID INT,
UpdatedAt DATETIME,
UpdatedBy DATETIME
)
GO
CREATE TABLE Products(
ProductID INT PRIMARY KEY,
ProductName VARCHAR(100)
)
GO
CREATE VIEW V_Order
AS
SELECT o.OrderID,o.CustomerID, p.ProductName
FROM Orders o
JOIN Products p
ON o.ProductID = p.ProductID
GO
CREATE SCHEMA repl
GO
CREATE TABLE repl.ReplicationTables
(
DBName sys.sysname NOT NULL DEFAULT('TestPublication'),
SchemaOwner sys.sysname NOT NULL DEFAULT('dbo'),
TableName sys.sysname NOT NULL
)
GO
INSERT INTO repl.ReplicationTables (tablename)
VALUES('Orders'),('Products'),('V_Order')
GO
USE TestPublication
GO
CREATE PROCEDURE CreatePublicationForDB( #databaseName sysname, #publicationName sysname = #databaseName, #allow_initialize_from_backup NVARCHAR(5) = 'true')
AS
BEGIN
BEGIN TRY
SET ANSI_WARNINGS ON
SET ANSI_PADDING ON
SET ANSI_NULLS ON
SET ARITHABORT ON
SET QUOTED_IDENTIFIER ON
SET ANSI_NULL_DFLT_ON ON
SET CONCAT_NULL_YIELDS_NULL ON
DECLARE #sp_replicationdboption varchar(MAX) = ' USE '+#databaseName +';',
#sp_addpulication VARCHAR(MAX) = ' USE '+#databaseName +';',
#sp_addpublication_snapshot VARCHAR(MAX) = ' USE '+#databaseName +';',
#sp_addarticle VARCHAR(MAX) = ' USE '+#databaseName +';',
#sp_startpublication_snapshot VARCHAR(MAX) = ' USE '+#databaseName +';'
DECLARE #allow_anonymous NVARCHAR(5) = CASE WHEN #allow_initialize_from_backup = 'false' OR #allow_initialize_from_backup IS NULL THEN 'true' ELSE 'false' END
DECLARE #immediate_sync NVARCHAR(5) = #allow_anonymous, #publisher sysname = ##SERVERNAME
-- set up database publication
SET #sp_replicationdboption += '
exec sp_replicationdboption #dbname = N'''+#databaseName+ ''',
#optname = N''publish'',
#value = N''true'''
-- Publication
SET #sp_addpulication += '
exec sp_addpublication #publication = N'''+#publicationName+ ''',
#description = N''Transactional publication of database '+#databaseName+' from Publisher '+#publisher+''',
#sync_method = N''concurrent'',
#retention = 0,
#allow_push = N''true'',
#allow_pull = N''true'',
#allow_anonymous = N'''+#allow_anonymous+ ''' ,
#enabled_for_internet = N''false'',
#snapshot_in_defaultfolder = N''true'',
#compress_snapshot = N''false'',
#ftp_port = 21,
#ftp_login = N''anonymous'',
#allow_subscription_copy = N''false'',
#add_to_active_directory = N''false'',
#repl_freq = N''continuous'',
#status = N''active'',
#independent_agent = N''true'',
#immediate_sync = N'''+#immediate_sync+ ''' ,
#allow_sync_tran = N''false'',
#autogen_sync_procs = N''false'',
#allow_queued_tran = N''false'',
#allow_dts = N''false'',
#replicate_ddl = 1,
#allow_initialize_from_backup = N'''+COALESCE(#allow_initialize_from_backup, 'false')+ ''' ,
#enabled_for_p2p = N''false'',
#enabled_for_het_sub = N''false'''
IF #allow_initialize_from_backup = 'false'
BEGIN
-- publication snapshot
SET #sp_addpublication_snapshot +='
exec sp_addpublication_snapshot #publication = N'''+#publicationName+ ''',
#frequency_type = 1,
#frequency_interval = 0,
#frequency_relative_interval = 0,
#frequency_recurrence_factor = 0,
#frequency_subday = 0,
#frequency_subday_interval = 0,
#active_start_time_of_day = 0,
#active_end_time_of_day = 235959,
#active_start_date = 0,
#active_end_date = 0,
#job_login = null,
#job_password = null,
#publisher_security_mode = 1'
SET #sp_startpublication_snapshot+=' exec sys.sp_startpublication_snapshot #publication = N'''+#publicationName+ ''''
END
-- Articles
IF OBJECT_ID('tempdb..#t') IS NULL
BEGIN
PRINT 'creating temp table t'
CREATE TABLE #t (NAME sysname,objectid INT, sch_owner sysname NULL, article sysname NOT NULL, isIndexed BIT NULL, IsSchemaBound BIT NULL, TYPE CHAR(2) NULL)
END
INSERT INTO #t(NAME,objectid, sch_owner,isIndexed,IsSchemaBound, TYPE,article)
EXEC('
USE '+#databaseName + '
SELECT f.Name, f.object_id,f.sch, f.IsIndexed,f.IsSchemaBound, f.type,CASE WHEN ROW_NUMBER() OVER (PARTITION BY f.name ORDER BY f.sch) > 1 THEN f.name + CAST((ROW_NUMBER() OVER (PARTITION BY f.name ORDER BY f.sch) - 1) AS VARCHAR(2)) ELSE f.name END AS Article
FROM(
SELECT t.Name, t.object_id,t.sch, IsIndexed,IsSchemaBound, type
FROM
(SELECT DBName, SchemaOwner, TableName
FROM TestPublication.repl.ReplicationTables
GROUP BY DBName, SchemaOwner, TableName )rt JOIN
(SELECT o.Name, o.object_id,s.name AS sch, objectproperty(o.object_id, ''IsIndexed'') AS IsIndexed,objectproperty(o.object_id, ''IsSchemaBound'') AS IsSchemaBound, o.type
FROM
sys.objects o
JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE o.type IN (''U'',''V'')
AND ObjectProperty(o.object_id, ''IsMSShipped'') = 0
AND (ObjectProperty(o.object_id, ''TableHasPrimaryKey'') = 1 OR ObjectProperty(o.object_id, ''TableHasPrimaryKey'') IS NULL)
) t ON rt.tablename = t.name AND rt.SchemaOwner = t.sch
WHERE rt.DBName = '''+#databaseName + '''
) f'
)
SELECT #sp_addarticle +=
'exec sp_addarticle
#publication = N''' +#databaseName +
''', #article = N''' +t.article+
''', #source_owner = N''' +t.sch_owner +
''', #source_object = N''' + t.NAME +
''', #type = N''' +
CASE WHEN t.type = 'U' THEN 'logbased'
WHEN t.type = 'V' AND (IsIndexed = 1 OR IsSchemaBound = 1 )THEN 'indexed view schema only'
WHEN t.type = 'V' AND IsIndexed = 0 THEN 'view schema only' END
+''', #description = null,#creation_script = null,#pre_creation_cmd = N''drop'',
#schema_option = '+
CASE WHEN t.type = 'U' THEN '0x000000000803509F'
WHEN t.type = 'V' THEN '0x0000000008000001' END+
',#destination_table = N'''+t.Name+
''',#destination_owner = N'''+t.sch_owner+''''+
CASE WHEN t.TYPE = 'U' THEN
', #identityrangemanagementoption = N''manual'',#vertical_partition = N''false'',
#ins_cmd = N''CALL sp_MSins_'+t.sch_owner+''+t.Name+
''', #del_cmd = N''CALL sp_MSdel_'+t.sch_owner+''+t.Name+''',
#upd_cmd = N''SCALL sp_MSupd_'+t.sch_owner+''+t.Name+''''
ELSE ''
END
+';'
FROM #t t
PRINT 'Now running sp_replicationdboption'
PRINT #sp_replicationdboption
EXEC(#sp_replicationdboption)
PRINT 'Now running sp_addpulication'
PRINT #sp_addpulication
EXEC(#sp_addpulication)
IF #allow_initialize_from_backup = 'false'
BEGIN
PRINT 'Now running sp_addpulication_snapshot and starting snapshot'
PRINT #sp_addpublication_snapshot
EXEC(#sp_addpublication_snapshot)
EXEC(#sp_startpublication_snapshot)
END
PRINT 'Now running sp_addarticles'
PRINT #sp_addarticle
EXEC(#sp_addarticle)
-- exec sp_droppublication #publication = N'Products'
END TRY
BEGIN CATCH
IF ##trancount > 0
ROLLBACK
DECLARE #ERROR_SEVERITY INT, #ERROR_STATE INT, #ERROR_MESSAGE NVARCHAR(4000)
SELECT #ERROR_SEVERITY = ERROR_SEVERITY(), #ERROR_STATE = ERROR_STATE(), #ERROR_MESSAGE = ERROR_MESSAGE()
RAISERROR(#ERROR_MESSAGE, #ERROR_SEVERITY, #ERROR_STATE)
END CATCH
END
GO
and finally execute
EXEC CreatePublicationForDB 'TestPublication'
-- drop replication in case you want to run the above again.
exec TestPublication.dbo.sp_droppublication #publication = 'TestPublication'
exec TestPublication.dbo.sp_replicationdboption #dbname = 'TestPublication', #optname = 'publish', #value = 'false'
-- cleanup database
DROP DATABASE TestPublication
Sorry, old post I know, but I ran into a very similar situation and got around it. I haven't found a workable solution anywhere else. I'm including my experience to help others.
Summary of my situation is that I have an msbuild process running a series of scripts from a manifest file (text file with a series of script names) within a transaction. The scripts that were intended to create and configure agent jobs always died with the same error. (invalid column name "file_exists")
Procs used in my failing script(s):
msdb.dbo.sp_add_category
msdb.dbo.sp_add_job
msdb.dbo.sp_add_jobstep
msdb.dbo.sp_update_job
msdb.dbo.sp_add_jobschedule
msdb.dbo.sp_add_jobserver
Commenting out the call to msdb.dbo.sp_add_jobstep allowed the script to complete.
I do have SQL command variables in the form #database_name=N'$(DatabaseName)' in the script as well. This led to some misdirected efforts to try to use escape macros as mentioned in the "Important" note under [ #command= ] 'command' on the documentation for sp_add_jobstep.
https://msdn.microsoft.com/en-us/library/ms187358.aspx
If I run the build up to, but not including, the job creation script and start over, it succeeds.
What I found, after much trial and error, was that, even though the procs are qualified as being in [MSDB], unless I actually included a USE statement, the process fails. By beginning the script with "USE [MSDB] GO" and then switching back to my build target (i.e. USE [MyBuildDB] GO), I no longer get the error.
My agent jobs create as expected, and several scripts within the build run without error.
It's hard to say what the problem is without seeing all of the code and having the schema. I'd recommend not creating a wrapper to create publication(s). The create publication scripts can be saved and executed on demand when needed - eliminating the need for a wrapper.