UFN_FINDCONSTITUENTMATCHES_3
Return
Return Type |
---|
table |
Parameters
Parameter | Parameter Type | Mode | Description |
---|---|---|---|
@TITLECODEID | uniqueidentifier | IN | |
@FIRSTNAME | nvarchar(50) | IN | |
@MIDDLENAME | nvarchar(50) | IN | |
@KEYNAME | nvarchar(100) | IN | |
@SUFFIXCODEID | uniqueidentifier | IN | |
@ADDRESSBLOCK | nvarchar(150) | IN | |
@POSTCODE | nvarchar(12) | IN | |
@COUNTRYID | uniqueidentifier | IN | |
@ISORGANIZATION | bit | IN | |
@ISGROUP | bit | IN | |
@LOOKUPID | nvarchar(100) | IN | |
@ALTERNATELOOKUPIDS | xml | IN | |
@EMAILADDRESS | nvarchar(100) | IN | |
@PHONENUMBER | nvarchar(100) | IN | |
@OVERALLMATCHTHRESHOLD | tinyint | IN | |
@AUTOMATCHTHRESHOLD | tinyint | IN |
Definition
Copy
CREATE function dbo.UFN_FINDCONSTITUENTMATCHES_3 (
@TITLECODEID uniqueidentifier,
@FIRSTNAME nvarchar(50),
@MIDDLENAME nvarchar(50),
@KEYNAME nvarchar(100),
@SUFFIXCODEID uniqueidentifier,
@ADDRESSBLOCK nvarchar(150),
@POSTCODE nvarchar(12),
@COUNTRYID uniqueidentifier,
@ISORGANIZATION bit,
@ISGROUP bit,
@LOOKUPID nvarchar(100),
@ALTERNATELOOKUPIDS xml,
@EMAILADDRESS nvarchar(100),
@PHONENUMBER nvarchar(100),
@OVERALLMATCHTHRESHOLD tinyint,
@AUTOMATCHTHRESHOLD tinyint
)
returns @MATCHES table (
CONSTITUENTID uniqueidentifier,
ADDRESSID uniqueidentifier,
EMAILADDRESSID uniqueidentifier,
PHONEID uniqueidentifier,
--
IDRESULT tinyint,
EMAILADDRESSRESULT tinyint,
TITLERESULT tinyint,
FIRSTNAMERESULT tinyint,
MIDDLENAMERESULT tinyint,
KEYNAMERESULT tinyint,
SUFFIXRESULT tinyint,
STREETNUMBERRESULT tinyint,
STREETNAMERESULT tinyint,
POSTCODERESULT tinyint,
PHONENUMBERRESULT tinyint,
-- scores are included for informational purposes, the results will be what is used to determine matches
FIRSTNAMESCORE tinyint,
MIDDLENAMESCORE tinyint,
KEYNAMESCORE tinyint,
STREETNUMBERSCORE tinyint,
STREETNAMESCORE tinyint,
POSTCODESCORE tinyint,
-- this constituent is not a match, but the two constituents may be a household
HOUSEHOLDMATCH bit,
COMPOSITESCORE int
)
begin
-- (1) match on lookup ID or alternate lookup IDs. Any matches found are exact matches. If any are found, we're done.
insert into @MATCHES (CONSTITUENTID, IDRESULT, COMPOSITESCORE)
select CONSTITUENTID, 0, 100
from dbo.UFN_FINDCONSTITUENTMATCHES_BYLOOKUPIDS(@LOOKUPID, @ALTERNATELOOKUPIDS)
if @@ROWCOUNT > 0
return;
-- No matches found by lookup ID or alternate ID, proceed with the fuzzy matching.
-- Clean incoming data
declare @CLEANFIRSTNAME nvarchar(50),
@CLEANMIDDLENAME nvarchar(50),
@CLEANKEYNAME nvarchar(100),
@STREETNUMBER nvarchar(12),
@STREETNAME nvarchar(150),
@CLEANPOSTCODE nvarchar(12),
@CLEANPHONENUMBER nvarchar(100)
select @CLEANFIRSTNAME = FIRSTNAME,
@CLEANMIDDLENAME = MIDDLENAME,
@CLEANKEYNAME = KEYNAME,
@STREETNUMBER = STREETNUMBER,
@STREETNAME = STREETNAME,
@CLEANPOSTCODE = POSTCODE
from dbo.UFN_CLEANCONSTITUENTSTRINGS_2(@FIRSTNAME, @MIDDLENAME, @KEYNAME, @ADDRESSBLOCK, @POSTCODE)
declare @LOGICALRESULTMAPPING dbo.UDT_GENERIC_NVARCHAR100_TINYINT;
insert into @LOGICALRESULTMAPPING
select CASENAME, RESULTCODE
from dbo.CONSTITUENTMATCHLOGICALRESULTMAPPING
-- (2) Get candidates by email address.
-- These candidates will be run through the main scoring algorithm. Any email match will be considered at least a manual review match.
-- If a single auto-match is found, we're done.
-- If multiple auto-matches are found, or only manual matches are found, we will also examine name/address-based candidates.
if @EMAILADDRESS <> ''
begin
insert into @MATCHES
select distinct
c.CONSTITUENTID,
-- only return addressid if the name/address is considered a match
case when s.BAILEDCOMPARISON = 1 then null else c.ADDRESSID end,
e.ID,
NULL,
1,
0,
s.TITLERESULT,
s.FIRSTNAMERESULT,
s.MIDDLENAMERESULT,
s.KEYNAMERESULT,
s.SUFFIXRESULT,
s.STREETNUMBERRESULT,
s.STREETNAMERESULT,
s.POSTCODERESULT,
NULL,
s.FIRSTNAMESCORE,
s.MIDDLENAMESCORE,
s.KEYNAMESCORE,
s.STREETNUMBERSCORE,
s.STREETNAMESCORE,
s.POSTCODESCORE,
s.HOUSEHOLDMATCH,
case
when s.BAILEDCOMPARISON = 1 then 70 --Email matches score at least 70
when s.COMPOSITESCORE < 98 then s.COMPOSITESCORE + 2 --Email matches add 2 to scores below 98
else s.COMPOSITESCORE
end
from dbo.EMAILADDRESS e
inner join dbo.SEARCHCONSTITUENT c on c.CONSTITUENTID = e.CONSTITUENTID
-- outer apply seems to resolve some performance problems with cross apply, since the UFN always returns a row, the results will be the same
outer apply dbo.UFN_COMPARECONSTITUENTS_4(@TITLECODEID, @CLEANFIRSTNAME, @CLEANMIDDLENAME, @CLEANKEYNAME, @SUFFIXCODEID, @STREETNUMBER, @STREETNAME, @CLEANPOSTCODE,
c.TITLECODEID, c.FIRSTNAME, c.MIDDLENAME, c.KEYNAME, c.SUFFIXCODEID, c.STREETNUMBER, c.STREETNAME, c.POSTCODE, c.COUNTRYID, 0, @ISORGANIZATION, @LOGICALRESULTMAPPING, 69) s -- Email matches won't be scored below 70, so only scores of 71 or more are meaningful. Using 69 since match can provide a +2 bonus score to get to 71.
where e.EMAILADDRESS = @EMAILADDRESS
and c.ISORGANIZATION = @ISORGANIZATION
and c.ISGROUP = @ISGROUP;
if @@ROWCOUNT > 0 and @AUTOMATCHTHRESHOLD > 0
begin
if ((select count(distinct CONSTITUENTID)
from @MATCHES
where COMPOSITESCORE >= @AUTOMATCHTHRESHOLD) = 1)
return
end
end
declare @NOEMAILRESULT tinyint = case when @EMAILADDRESS = '' then 4 else 6 end
declare @NOPHONERESULT tinyint = case when @CLEANPHONENUMBER = '' then 4 else 6 end
-- (3) Find candidates by phone.
if @PHONENUMBER <> ''
begin
set @CLEANPHONENUMBER = dbo.UFN_PHONE_REMOVEFORMATTING(@PHONENUMBER);
declare @NULLID uniqueidentifier = cast('00000000-0000-0000-0000-000000000000' as uniqueidentifier)
insert into @MATCHES
select distinct
c.CONSTITUENTID,
-- only return addressid if the name/address is considered a match
case when s.BAILEDCOMPARISON = 1 then null else c.ADDRESSID end,
NULL,
p.ID,
1,
@NOEMAILRESULT,
s.TITLERESULT,
s.FIRSTNAMERESULT,
s.MIDDLENAMERESULT,
s.KEYNAMERESULT,
s.SUFFIXRESULT,
s.STREETNUMBERRESULT,
s.STREETNAMERESULT,
s.POSTCODERESULT,
0,
s.FIRSTNAMESCORE,
s.MIDDLENAMESCORE,
s.KEYNAMESCORE,
s.STREETNUMBERSCORE,
s.STREETNAMESCORE,
s.POSTCODESCORE,
s.HOUSEHOLDMATCH,
case
when s.BAILEDCOMPARISON = 1 then 70 --Phone matches score at least 70
when s.COMPOSITESCORE < 98 then s.COMPOSITESCORE + 2 --Phone matches add 2 to scores below 98
else s.COMPOSITESCORE
end
from dbo.PHONE p
inner join dbo.SEARCHCONSTITUENT c on c.CONSTITUENTID = p.CONSTITUENTID
outer apply dbo.UFN_COMPARECONSTITUENTS_4(@TITLECODEID, @CLEANFIRSTNAME, @CLEANMIDDLENAME, @CLEANKEYNAME, @SUFFIXCODEID, @STREETNUMBER, @STREETNAME, @CLEANPOSTCODE,
c.TITLECODEID, c.FIRSTNAME, c.MIDDLENAME, c.KEYNAME, c.SUFFIXCODEID, c.STREETNUMBER, c.STREETNAME, c.POSTCODE, c.COUNTRYID, 0, @ISORGANIZATION, @LOGICALRESULTMAPPING, 69) s -- Phone matches won't be scored below 70, so only scores of 71 or more are meaningful. Using 69 since match can provide a +2 bonus score to get to 71.
where p.NUMBERNOFORMAT = @CLEANPHONENUMBER
and c.ISORGANIZATION = @ISORGANIZATION
and c.ISGROUP = @ISGROUP
and coalesce(p.COUNTRYID,c.COUNTRYID,@NULLID) = coalesce(@COUNTRYID,p.COUNTRYID,c.COUNTRYID,@NULLID)
-- constituent not already found by email address
and not exists(select 1 from @MATCHES where CONSTITUENTID = c.CONSTITUENTID);
end
--Caching values for query checks below
declare @KEYNAME4 nvarchar(4) = left(@CLEANKEYNAME,4)
declare @FIRSTNAME3 nvarchar(3) = left(@CLEANFIRSTNAME,3)
declare @STREETNAME4 nvarchar(4) = left(@STREETNAME,4)
declare @POSTCODE3 nvarchar(3) = left(@CLEANPOSTCODE,3)
declare @CLEANFIRSTNAME3 nvarchar(3) = left(@CLEANFIRSTNAME,3)
-- (4) Find candidates by name and address.
if @CLEANKEYNAME <> '' and @CLEANPOSTCODE <> ''
begin
-- Force checks that have to pass for constituent to have any chance at matching above overall match threshold
-- This is a help in automatch-only cases where the overall threshold is as high as @AUTOMATCHTHRESHOLD
declare @FORCESTREETNUMBERCHECK bit = 0
declare @FORCEPOSTCODECHECK bit = 0
if @STREETNUMBER <> '' and @OVERALLMATCHTHRESHOLD > 100 - (select DEDUCTION from dbo.UFN_CONSTITUENTMATCH_STREETNUMBERSCOREDEDUCTION_BYRESULT(1))
set @FORCESTREETNUMBERCHECK = 1
if @CLEANPOSTCODE <> '' and @OVERALLMATCHTHRESHOLD > 100 - (select DEDUCTION from dbo.UFN_CONSTITUENTMATCH_POSTCODESCOREDEDUCTION_BYRESULT(1))
set @FORCEPOSTCODECHECK = 1
--*********************************************************
-- THIS QUERY IS CAREFULLY WRITTEN TO MAKE USE OF THREE AVAILABLE INDEXES ON THE SEARCHCONSTITUENT TABLE, referred to as universes 1-3 below.
-- Do not make any changes to this query without verifying that the execution plan, and specifically the FULL use of the three indexes (all columns used in the lookup), remains intact.
-- *********************************************************
insert into @MATCHES
select c.CONSTITUENTID,
c.ADDRESSID,
NULL,
NULL,
1,
@NOEMAILRESULT,
s.TITLERESULT,
s.FIRSTNAMERESULT,
s.MIDDLENAMERESULT,
s.KEYNAMERESULT,
s.SUFFIXRESULT,
s.STREETNUMBERRESULT,
s.STREETNAMERESULT,
s.POSTCODERESULT,
@NOPHONERESULT,
s.FIRSTNAMESCORE,
s.MIDDLENAMESCORE,
s.KEYNAMESCORE,
s.STREETNUMBERSCORE,
s.STREETNAMESCORE,
s.POSTCODESCORE,
s.HOUSEHOLDMATCH,
s.COMPOSITESCORE
from dbo.SEARCHCONSTITUENT c
outer apply dbo.UFN_COMPARECONSTITUENTS_4(@TITLECODEID, @CLEANFIRSTNAME, @CLEANMIDDLENAME, @CLEANKEYNAME, @SUFFIXCODEID, @STREETNUMBER, @STREETNAME, @CLEANPOSTCODE,
c.TITLECODEID, c.FIRSTNAME, c.MIDDLENAME, c.KEYNAME, c.SUFFIXCODEID, c.STREETNUMBER, c.STREETNAME, c.POSTCODE, c.COUNTRYID, 0, @ISORGANIZATION, @LOGICALRESULTMAPPING, @OVERALLMATCHTHRESHOLD) s
where c.ISORGANIZATION = @ISORGANIZATION
and c.ISGROUP = @ISGROUP
and c.COUNTRYID = isnull(@COUNTRYID,c.COUNTRYID)
and (
@FORCESTREETNUMBERCHECK = 0 or
c.STREETNUMBER = '' or
c.STREETNUMBER = @STREETNUMBER or
c.STREETNUMBER like @STREETNUMBER + '-%' or
@STREETNUMBER like c.STREETNUMBER + '-%'
)
--
-- universe 1 - postcode, keyname soundex
and ((c.POSTCODE = @CLEANPOSTCODE and
c.KEYNAME4 = @KEYNAME4) or
--
-- universe 2 - postcode, street name soundex, first name soundex
(c.POSTCODE = @CLEANPOSTCODE and
c.STREETNAMESOUNDEX = soundex(@STREETNAME) and
c.FIRSTNAME3 = @FIRSTNAME3) or
--
-- universe 3 - 1st 3 characters of postcode, 1st 4 characters of keyname,
-- 1st 4 characters of street name, street number
((@FORCEPOSTCODECHECK = 0 or
c.POSTCODE = @CLEANPOSTCODE) and
c.POSTCODE3 = @POSTCODE3 and
c.KEYNAMESOUNDEX = soundex(@CLEANKEYNAME) and
c.STREETNAME4 = @STREETNAME4 and
c.STREETNUMBER = @STREETNUMBER)
)
-- constituent not already found by email address or phone
and not exists(select 1 from @MATCHES where CONSTITUENTID = c.CONSTITUENTID);
-- ******************************
-- END OF QUERY - see important note above regarding changes to this query
-- ******************************
end
-- (5) Find candidates by name only (either no incoming address, or no existing records with a matching address).
if @CLEANKEYNAME <> '' and not exists(select 1 from @MATCHES)
begin
-- prevent long-running searches for names like "Friend of X" or "Anonymous"
if not exists(select 'x' from dbo.SEARCHCONSTITUENTEXCLUDE
where KEYNAME = @CLEANKEYNAME
and FIRSTNAME3 = @CLEANFIRSTNAME3)
begin
-- For performance reasons, search first for records with no address.
-- If we don't have an incoming address, these will score higher than any matches we might find with addresses.
-- If we have an incoming address, existing constituents with addresses would have been matched above so no reason to search those again.
insert into @MATCHES
select distinct
c.CONSTITUENTID,
NULL,
NULL,
NULL,
1,
@NOEMAILRESULT,
s.TITLERESULT,
s.FIRSTNAMERESULT,
s.MIDDLENAMERESULT,
s.KEYNAMERESULT,
s.SUFFIXRESULT,
s.STREETNUMBERRESULT,
s.STREETNAMERESULT,
s.POSTCODERESULT,
@NOPHONERESULT,
s.FIRSTNAMESCORE,
s.MIDDLENAMESCORE,
s.KEYNAMESCORE,
s.STREETNUMBERSCORE,
s.STREETNAMESCORE,
s.POSTCODESCORE,
s.HOUSEHOLDMATCH,
s.COMPOSITESCORE
from dbo.SEARCHCONSTITUENT c
outer apply dbo.UFN_COMPARECONSTITUENTS_4(@TITLECODEID, @CLEANFIRSTNAME, @CLEANMIDDLENAME, @CLEANKEYNAME, @SUFFIXCODEID, @STREETNUMBER, @STREETNAME, @CLEANPOSTCODE,
c.TITLECODEID, c.FIRSTNAME, c.MIDDLENAME, c.KEYNAME, c.SUFFIXCODEID, c.STREETNUMBER, c.STREETNAME, c.POSTCODE, c.COUNTRYID, 0, @ISORGANIZATION, @LOGICALRESULTMAPPING, @OVERALLMATCHTHRESHOLD) s
where c.KEYNAME = @CLEANKEYNAME
and c.FIRSTNAME3 = @CLEANFIRSTNAME3
and c.POSTCODE = ''
and c.ISORGANIZATION = @ISORGANIZATION
and c.ISGROUP = @ISGROUP;
-- If we don't have an address and didn't find any records without an address, try existing constituents with an address.
if @CLEANPOSTCODE = '' and not exists(select 1 from @MATCHES)
insert into @MATCHES
select distinct
c.CONSTITUENTID,
NULL,
NULL,
NULL,
1,
@NOEMAILRESULT,
s.TITLERESULT,
s.FIRSTNAMERESULT,
s.MIDDLENAMERESULT,
s.KEYNAMERESULT,
s.SUFFIXRESULT,
s.STREETNUMBERRESULT,
s.STREETNAMERESULT,
s.POSTCODERESULT,
@NOPHONERESULT,
s.FIRSTNAMESCORE,
s.MIDDLENAMESCORE,
s.KEYNAMESCORE,
s.STREETNUMBERSCORE,
s.STREETNAMESCORE,
s.POSTCODESCORE,
s.HOUSEHOLDMATCH,
s.COMPOSITESCORE
from dbo.SEARCHCONSTITUENT c
outer apply dbo.UFN_COMPARECONSTITUENTS_4(@TITLECODEID, @CLEANFIRSTNAME, @CLEANMIDDLENAME, @CLEANKEYNAME, @SUFFIXCODEID, @STREETNUMBER, @STREETNAME, @CLEANPOSTCODE,
c.TITLECODEID, c.FIRSTNAME, c.MIDDLENAME, c.KEYNAME, c.SUFFIXCODEID, c.STREETNUMBER, c.STREETNAME, c.POSTCODE, c.COUNTRYID, 0, @ISORGANIZATION, @LOGICALRESULTMAPPING, @OVERALLMATCHTHRESHOLD) s
where c.KEYNAME = @CLEANKEYNAME
and c.FIRSTNAME3 = @CLEANFIRSTNAME3
and c.POSTCODE <> ''
and c.ISORGANIZATION = @ISORGANIZATION
and c.ISGROUP = @ISGROUP;
end
end
-- If the email or phone are different, we want to subtract 1 so the score reflects the difference.
-- However, in these situations, we want to ensure that we (a) don't auto match and (b) don't take a potential match out of manual review range.
-- Thus we ensure that the score is no more than 94 and we keep it at 70 if it was 70.
if @EMAILADDRESS <> ''
begin
update M
set COMPOSITESCORE = case when COMPOSITESCORE = 70 then COMPOSITESCORE when COMPOSITESCORE > 95 then 94 else COMPOSITESCORE - 1 end
from @MATCHES M
where M.EMAILADDRESSRESULT > 0
and exists (select 'x' from dbo.EMAILADDRESS E where E.CONSTITUENTID = M.CONSTITUENTID)
end
if @PHONENUMBER <> ''
begin
-- if phone wasn't processed (phone number result is null) try finding a match and increase the score
update M
set COMPOSITESCORE = case when COMPOSITESCORE < 98 then COMPOSITESCORE + 2 else COMPOSITESCORE end,
PHONEID = P.ID,
PHONENUMBERRESULT = 0
from @MATCHES M
inner join dbo.PHONE P on P.CONSTITUENTID = M.CONSTITUENTID
where M.PHONENUMBERRESULT is null
and (P.COUNTRYID = @COUNTRYID or P.COUNTRYID is null or @COUNTRYID is null)
and P.NUMBERNOFORMAT = @CLEANPHONENUMBER
-- decrease the score if the incoming phone does not have a match
update M
set COMPOSITESCORE = case when COMPOSITESCORE = 70 then COMPOSITESCORE when COMPOSITESCORE > 95 then 94 else COMPOSITESCORE - 1 end
from @MATCHES M
where coalesce(M.PHONENUMBERRESULT,1) > 0
and exists (select 'x' from dbo.PHONE P where P.CONSTITUENTID = M.CONSTITUENTID)
end
return
end