This question is kind of multifaceted. First, what I'm trying to actually accomplish:
I am in an environment where there is not really heavy data validation on inputs. So there is lots of opportunity for errors from a business logic perspective. This alone is not the biggest sin, but there is no form of followup/reconciliation that checks for the existence of conditions that violate business rules. People just discover them when looking at reports that "don't smell right."
Without talking about the upgrades to infrastructure that would be the most suitable solution to prevent erroneous data in the first place, what I'm looking at as a first step is shedding some light on errors or possible errors so they can be proactively resolved, rather than waiting for end users to "discover" them (and feeling that it's necessary to "sniff test" every single report they consume). So what I'm trying to do is create an easy to use template for non-sql geniuses to be able to set up basic error monitoring.
So, here's my idea, what I don't like about it, and then I welcome any other ideas or alternatives.
Checking for errors is simple. There are very basic tests that can be run like:
select InterestingField
from TableWithErrors
where ConditionThatRepresentProblems
By definition, we expect the query to return no results. By nature, pretty much all of the queries checking for errors can be almost as small/simple. A real-life example may look more like:
--look for foreignpin duplicates where there should not be any
select
ai.ForeignPin
, ai.AccountName
, ai.AcctURL
, ai.AccountManager
from
DB.dbo.vAccountIndex ai
where
ai.ForeignPin in
(
select ai.ForeignPin
from DB.dbo.vAccountIndex ai
where ai.ForeignPin is not null
group by ai.ForeignPin
having count(ai.Foreignpin) > 1
)
order by
ai.ForeignPin
, ai.AccountName
I'd like to be able to set up a simple template where a query like that above can be pasted in verbatim, and the value of a couple variables can updated for emailto, etc. The idea would be that if an error exists, the appropriate person will be emailed with the offending records, otherwise nothing would happen (or a passive "green light" message could be passed through).
This would be set up in a job, and any time someone has a new error that they want to monitor for, they can just come up with a simple query that checks if the error conditions exist, and emails them (or party responsible for data) automatically for resolution.
So here's the command I put together that does not work:
declare
@SendTo varchar(255)
, @from_address varchar(255)
, @Subject varchar(255)
, @body varchar(8000)
, @@SQL nvarchar(4000)
set @SendTo = '[email protected]'
set @from_address = '[email protected]'
set @Subject = 'Foregin pin duplicate'
set @body = 'There is a duplicate value in Foreign pin field of Account table. Duplicates in this field may result in double counting of sales, or failure of sales transaction-related tasks.'
set @@SQL = 'select * from @@results'
--put your error sniffing query here, stuffing results into this table variable
declare @@results table
(
ForeignPin varchar(255)
, AccountName varchar(36)
, AcctURL varchar(255)
, AccountManager varchar(255)
)
insert into @@results
select
ai.ForeignPin
, ai.AccountName
, ai.AcctURL
, ai.AccountManager
from
DB.dbo.vAccountIndex ai
where
ai.ForeignPin in
(
select ai.ForeignPin
from DB.dbo.AccountIndex ai
where ai.ForeignPin is not null
group by ai.ForeignPin
having count(ai.Foreignpin) > 1
)
order by
ai.ForeignPin
, ai.FuneralHome
--the dbmail doesn't seem to like the @@sql variable...
if exists (select * from @@results)
BEGIN
EXEC msdb.dbo.sp_send_dbmail
-- @profile_name = 'your mail profile',
@recipients = @SendTo
, @body = @body
, @subject = @Subject
-- to send file attachments (if any)
--, @file_attachments = 'L:\logs.TXT',
-- send query results
, @query = @@SQL
END
else print 'No Error Found';
I quickly discovered this would not work due to the well-documented sp_send_dbmail technet article saying explicitly:
"Note that the query is executed in a separate session, so local variables in the script calling sp_send_dbmail are not available to the query."
The solution to this problem that I've found thus far have been to simply wrap the entire query, sp_send_dbmail and all into the dynamic sql text.
I do not like this solution for two basic reasons. 1) you'd have to write the query twice - once to check if the condition exists, outside of dynamic sql, then again inside the dynamic to send the email. 2) dynamic sql is ugly and hard to read. if you have any apostrophes in the code, you have to double those up for dynamic, then debug, etc, etc.
I wanted to have a simple to use solution for people who are not power users to be able to write a really simple query looking for errors, write in their email, and have that condition monitored for errors.
Can anyone suggest a different way of looking at this process with emphasis on simple for end users. It's ok if I have to set up something a little more complicated on the backend, as long as the end users can paste a simple query, enter their email, and be done, knowing that if the query ever returns results, they will be notified immediately?
For the record, this solution may be implemented on an instance running SQL Server 2005, or SQL Server 2012.