views:

786

answers:

2

I have a job that performs several validation checks on rows in several tables in a database. If the check fails it logs the failure in a table that. The information that is logged includes the table name, a uniqueidentifier value of the row that failed, which check it failed, and which job was being run at the time. Here's the simplified table definition of the log

CREATE TABLE [tblSY_ValidationFieldFailures](
    [pkValidationFieldFailure] [int] IDENTITY(1,1) NOT NULL,
    [fkJobID] [int] NOT NULL,
    [fkValidationFieldFailureType] [int] NOT NULL,
    [TableName] nvarchar(128),
    [TableUniqueIdentifier] [nvarchar](100) NULL)

I'd like to write a function that returns the number of rows failed given a certain table and jobID (i.e. fnGetNumberOfFailedRows(@JobID, @TableName)). I tried something similar to the following:

CREATE FUNCTION fnGetNumberOfRowsThatFailedValidationCheck 
(
    @pkJobID int,
    @TableName nvarchar(128)
)
RETURNS int
AS
BEGIN
    -- Declare the return variable here
    DECLARE @NumFailedRows int

    Select fkJobID, 
           TableUniqueIdentifier, 
           TableName 
    From tblSY_ValidationFieldFailures
     Where fkJobID=@pkJobID And TableName=@TableName
                    Group By fkJobID, TableName, TableUniqueIdentifier

    SET @NumFailedRows = @@ROWCOUNT

    RETURN @NumFailedRows    
END

But of course you can't have that Select statement inside a function. Is there a way to do what I want inside a function or do I have to so the stored procedure route?

+4  A: 

You could use a count(*) statement in your select, and assign that properly, such as:

CREATE FUNCTION fnGetNumberOfRowsThatFailedValidationCheck 
(
    @pkJobID int,
    @TableName nvarchar(128)
)
RETURNS int
AS
BEGIN
-- Declare the return variable here
DECLARE @NumFailedRows int

Select @NumFailedRows = count(*) 
From tblSY_ValidationFieldFailures
    Where fkJobID=@pkJobID And TableName=@TableName
                Group By fkJobID, TableName, TableUniqueIdentifier

--SET @NumFailedRows = @@ROWCOUNT

RETURN @NumFailedRows    
END
Erich
Unfortunately that will just give me the count of how many different tests a particular row failed; e.g. if UniqueIdentifier=1 and fkJobID=1 and TableName='table1' and that row failed fkValidationFieldFailureType 1, 6, and 7 Count(*) will return 3. Basically doing that returns a count for each row that failed a test
Dustin Hodges
You need to wrap it so that the COUNT(*) is the count of the groups, not the count within each group.
Cade Roux
+2  A: 

This should do it for you:

    CREATE FUNCTION fnGetNumberOfRowsThatFailedValidationCheck 
 (   
 @pkJobID int,    
 @TableName nvarchar(128)
 )
RETURNS int
AS

BEGIN

-- Declare the return variable here
DECLARE @NumFailedRows int

SELECT @NumFailedRows = count(*) 
FROM (
 Select 
  fkJobID,            
  TableUniqueIdentifier,            
  TableName 
 From tblSY_ValidationFieldFailures    
 Where fkJobID=@pkJobID
 And TableName=@TableName
 Group By fkJobID, TableName, TableUniqueIdentifier
 ) a

RETURN @NumFailedRows

END
data jockey
Thanks this worked. I tried this before without the alias and it got a syntax error. Do you know why the a is required at the end?
Dustin Hodges
Glad I could help. I can't say exactly why there is a need for an alias, except to say that all fields must be able to be fully-qualified (most of the time, the engine handles this for you), and without a name for the derived table/resultset, you have no name for the source of any referenced fields. Just guessing, though.
data jockey