0

我正在尝试创建一个 SQL UDF 或语句来解析一个自由文本字段并从中找到国家名称,但我无法成功。

为了给你们提供完整的上下文,我有一个包含交易详细信息的交易表(下面的 tbltransactions),其中一个字段是这个自由文本字段。理想情况下,这应包含收款人姓名、收款人地址和收款人国家/地区(按此顺序)。但正如您对自由文本字段所期望的那样,存在各种可能的组合。这也意味着一个国家的名称可能拼写错误、缩写、缩短或完全丢失。幸运的是,大多数交易都在文本块的末尾指定了国家!表格中有另一个字段,用户在其中输入 3 个字符的国家代码(必填)。这可能与他在自由文本字段中输入的内容匹配,也可能不匹配。下面是表中的虚拟数据:

TransID     ISOCode BeneAddress
------------------- -----------
20          IRN     aaaa bb cccc Islamic Rupublic of Iran  
19          IRN     aaaa bb cccc Iran, Islamic Republic of

现在,我制作了一个查找表 (tblCountryMappings),其中存储了所有国家/地区及其名称可能变体的列表(其中大多数!)。

例如。“马其顿共和国”、“马其顿、前南斯拉夫共和国”、“马其顿”、“马其顿”等。

以下是该表的虚拟数据:

ID  ISONumericCode  countryName                 matchIdentifier            matchIdentifierType
----------------------------------------------------------------------------------------------
209  364            Iran, Islamic Republic of   IR                         ISOAlphaCode_2
210  364            Iran, Islamic Republic of   IRN                        ISOAlphaCode_3
495  364            Iran, Islamic Republic of   Iran                       Short_Name
1163 364            Iran, Islamic Republic of   Iran, Islamic Republic of  Original_Name
1309 364            Iran, Islamic Republic of   Islamic Rupublic of Iran   Alternate_Name

如您所见,表之间存在一对多映射。目标是能够分析交易并找到它的目标国家(主要基于自由文本字段,而不仅仅是ISO 代码)。例如,我们应该可以看到 Transaction 123 在 ISO 代码中有“Iraq”,在自由文本中有“Iran”,自由文本匹配在 ISO 3 字符“IRN”上。我还需要确保匹配在边界情况下有效(例如行尾,用引号括起来),但如果它位于文本块的中间(例如不匹配沙特阿拉伯 2 字符代码“SA”到任何叫“塞缪尔”的人)。

我编写了这个基本脚本来从自由文本中提取最后一个单词,然后可以使用它来加入 tblCountryMappings 中的 matchIdentifier ,但这显然是一个非常糟糕的尝试。

select 
    beneaddress
    ,SUBSTRING(beneaddress, 
               case when CHARINDEX(' ',REVERSE(beneaddress)) = 0 then 1 
                    else LEN(beneaddress) - CHARINDEX(' ',REVERSE(LTRIM(RTRIM(beneaddress))))+2
               end
    ,LEN(beneaddress)) as Country
from
    tblTransactions

如果您能帮助我构建此解决方案,我们将不胜感激。如果我违反了任何发帖规则,请原谅我,因为这是我第一次。随时询问更多信息,我会尽快发布。

提前非常感谢。

干杯

4

2 回答 2

0

如果我理解你的问题。

以下将返回最高匹配命中数。它确实需要下面列出的 PARSING 函数:

创建示例数据

Declare @YouTable table (TransID int,ISOCode varchar(50),BeneAddress varchar(500))
Insert Into @YouTable values 
(20,'IRN','aaaa bb cccc Islamic Rupublic of Iran'),
(19,'IRN','aaaa bb cccc Iran, Islamic Republic of')

Declare @ISO table (ID int,ISONumericCode int,countryName varchar(50),matchIdentifier varchar(50),matchIdentifierType varchar(50))
Insert Into @ISO values
(209  ,364,'Iran, Islamic Republic of','IR',                       'ISOAlphaCode_2'),
(210  ,364,'Iran, Islamic Republic of','IRN',                      'ISOAlphaCode_3'),
(495  ,364,'Iran, Islamic Republic of','Iran',                     'Short_Name'),
(1163 ,364,'Iran, Islamic Republic of','Iran, Islamic Republic of','Original_Name'),
(1309 ,364,'Iran, Islamic Republic of','Islamic Rupublic of Iran' ,'Alternate_Name')

实际 SQL

;with cteBase as (
        Select A.*,B.*,C.*
            From  @YouTable A
            Cross Apply (Select * from [dbo].[udf-Str-Parse](A.BeneAddress,' ')  ) B
            Cross Apply (Select * from @ISO where matchIdentifier like '%'+B.RetVal+'%') C),    
      cteSumm as (
        Select TransID,ID,RowNr=Row_Number() over (Partition By TransID Order by Count(*) Desc)
        From cteBase
        Group By TransID,ID
)
Select B.*,C.*
 From  cteSumm A
 Join  @YouTable B on (A.RowNr=1 and A.TransID = B.TransID)
 Join  @ISO C      on (A.RowNr=1 and A.ID=C.ID)

退货

在此处输入图像描述

UDF

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimiter varchar(10))
Returns Table 
As
Return (  
    Select RetSeq = Row_Number() over (Order By (Select null))
          ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
    From (Select x = Cast('<x>'+ Replace(@String,@Delimiter,'</x><x>')+'</x>' as xml).query('.')) as A 
    Cross Apply x.nodes('x') AS B(i)
);
--Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse]('John||Cappelletti||was||here','||')
于 2016-09-29T17:47:41.383 回答
0

我怀疑那里有一个完美的解决方案,因为我可以想象个别街道名称或州名可能与某些国家名称相似的奇怪场景。话虽如此,您可以将查找表加入事务表使用LIKE语句。这样您就可以使用正则表达式来匹配地址中的国家/地区。国家/地区名称将位于末尾或在前面或结尾处以“,”或空格分隔。它应该会稍微简化您的查询,但正如我所提到的,它并不完美。

以下示例显示了查询的外观。

DECLARE @tbltransactions TABLE
(
     TransID        INT
    ,ISOCode        NVARCHAR(3)
    ,BeneAddress    NVARCHAR(100)
)

DECLARE @tblCountryMappings TABLE
(
     ID                 INT IDENTITY
    ,CountryName        NVARCHAR(100)
    ,MatchIdentifier    NVARCHAR(100)
)

INSERT INTO @tbltransactions
(
     TransID    
    ,ISOCode    
    ,BeneAddress
)
VALUES
(1          ,'IRN'     ,'aaaa bb cccc Islamic Rupublic of Iran') ,
(2          ,'IRN'     ,'aaaa bb cccc "Iran", Islamic Republic of'),
(3          ,'IRN'     ,'aaRSAbb cccc IRN'),
(4          ,'IRN'     ,'aaaa bb cccc IR'),
(5          ,'IRN'     ,'aaaa bb cccc The Country of Fred')


INSERT INTO @tblCountryMappings
(       
     CountryName    
    ,MatchIdentifier
)
VALUES
('Iran, Islamic Republic of',   'IR'),         
('Iran, Islamic Republic of',   'IRN'),         
('Iran, Islamic Republic of',   'Iran'),
('South Africa, Republic of',   'RSA'),
('South Africa, Republic of',   'R.S.A.'),
('South Africa, Republic of',   'South Africa')


SELECT      T.TransID
            ,T.BeneAddress
            ,ISNULL(M.CountryName, '< Could not match country>') AS CountryName
            ,M.MatchIdentifier
FROM        @tbltransactions    T
LEFT OUTER JOIN @tblCountryMappings M ON 
                ( 
                        (T.BeneAddress LIKE '%[, "]' + M.MatchIdentifier + '[, "]%') -- Match any address which contains a word that start with a comma or space or quote ([, "]) and is then followed by the MatchIdentifier and then end with either a comma or space or quote.
                                OR
                        (T.BeneAddress LIKE '%[, "]' + M.MatchIdentifier ) -- Match any address which contains a word that start with a comma or space or quote ([, "]) and is then ends with the MatchIdentifier.
                                OR
                        (T.BeneAddress LIKE M.MatchIdentifier + '[, "]%') -- Match any address which contains a word that start with the MatchIdentifier and then end with either a comma or space or quote.
                                OR
                        (T.BeneAddress LIKE M.MatchIdentifier ) -- Match the address with an exact match of the MatchIdentifier
                )

在上面的示例中,sql 会将 BeneAddress 与基于 MatchIdentifier 字段的值生成的正则表达式进行匹配。

tblCountryMappings 中的示例 MatchIdentifier 字段将具有以下伊朗值。

  • 红外
  • 国际注册网络
  • 伊朗

这将生成以下正则表达式:

  • %[, "]IR[, "]% - 匹配任何包含以逗号或空格或引号 ([, "]) 开头的单词,然后是 IR,然后以逗号或空格结尾的字符串或引用。
  • %[, "]IRN[, "]% - 匹配任何包含以逗号或空格或引号 ([, "]) 开头的单词,然后是 IRN,然后以逗号或空格结尾的字符串或引用。
  • %[, "]Iran[, "]% - 匹配任何包含以逗号或空格或引号 ([, "]) 开头的单词,然后是伊朗,然后以逗号或空格结尾的字符串或引用。

为了匹配国家/地区可能位于字符串末尾的可能性,我们包含了一个附加OR条件,其中没有为结尾定义模式匹配。与匹配国家名称可能位于字符串开头的可能性类似,我们包含一个附加OR条件,其中没有为开头定义模式匹配。

于 2016-09-29T17:48:43.703 回答