首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何逐个处理SQL字符串来构建匹配权重?

如何逐个处理SQL字符串来构建匹配权重?
EN

Stack Overflow用户
提问于 2016-07-19 01:37:41
回答 1查看 89关注 0票数 0

问题:我需要在表单上显示用户输入的字段,根据某些查找条件是动态的。

我目前的解决方案:我已经创建了一个SQL表,其中包含一些字段输入条件,它基于一个相对简单的匹配条件。匹配条件基本上是这样的: Lookup值以match Code开头,通过LEN比较找到最精确的匹配项。

代码语言:javascript
复制
select 
      f.[IS_REQUIRED]
    , f.[MASK]
    , f.[MAX_LENGTH]
    , f.[MIN_LENGTH]
    , f.[RESOURCE_KEY]
    , f.[SEQUENCE]
from [dbo].[MY_RECORD] r with(nolock)
inner join [dbo].[ENTRY_FORMAT] f with(nolock)
    on  r.[LOOKUP_VALUE] like f.[MATCH_CODE]

-- Logic to filter by single, most-precise record match.
cross apply (
    select f1.[SEQUENCE]
    from [dbo].[ENTRY_FORMAT] f1 with(nolock)
    where f.[SEQUENCE] = f1.[SEQUENCE]
      and s.[MATCH_CODE] like f1.[MATCH_CODE]
    group by f1.[SEQUENCE]
    having len(f.[MATCH_CODE]) = max(len(f1.[MATCH_CODE]))
) tFilter

where r.[ID] = @RecordId

当前的问题是,必须针对每个匹配计算每个调用的最精确匹配。此外,我目前只能在MATCH_CODE中支持%。(例如,'%'是所有LOOKUP_VALUE的默认设置,而输入'12%'将更精确地匹配LOOKUP_VALUE of '12345',而MATCH_CODE of '12345'显然应该是最精确的匹配。)但是,我想添加对[4-7]等通配符的支持。离开LEN,这肯定是错误的,因为'[4-7]'增加了很多长度,但是,例如,'12345'仍然是'123[4-7]'的理想匹配

我想要的更新是:向ENTRY_FORMAT添加一个MATCH_WEIGHT列,我可以通过insert/update时的触发器对其进行更新。对于我的初始实现,我只是在寻找一些可以逐个字符地通过MATCH_CODE,增加MATCH_WEIGHT,但在这样做时只将[..]视为单个字符的东西。是否有好的机制(UDF - SQL或CLR?光标?)通过迭代varchar字段的字符来以这种方式计算值?例如,每个非通配符增加两个MATCH_WEIGHT,可能在一个通配符上增加一个;细节有待进一步考虑和解决……

我们的目标是使用更像这样的查询:

代码语言:javascript
复制
select 
      f.[IS_REQUIRED]
    , f.[MASK]
    , f.[MAX_LENGTH]
    , f.[MIN_LENGTH]
    , f.[RESOURCE_KEY]
    , f.[SEQUENCE]
from [dbo].[MY_RECORD] r with(nolock)

-- Logic to filter by single, most-precise record match.
cross apply (
    select top 1
          f1.[MATCH_CODE]
        , f1.[SEQUENCE]
    from [dbo].[ENTRY_FORMAT] f1 with(nolock)
    where r.[LOOKUP_VALUE] like f1.[MATCH_CODE]
    group by f1.[SEQUENCE]
    order by f1.[MATCH_WEIGHT] desc
) tFilter
inner join [dbo].[ENTRY_FORMAT] f with(nolock)
    on  f.[MATCH_CODE] = tFilter.[MATCH_CODE]
    and f.[SEQUENCE] = tFilter.[SEQUENCE]

where r.[ID] = @RecordId

注意:我意识到这是一个相对脆弱的设置。ENTRY_FORMAT记录只由开发人员输入,他们知道这些限制,所以现在假设输入了有效数据,并且不会导致匹配冲突。

在一些帮助下,我已经提出了一个实现(答案如下),但我仍然不确定我的总体设计,所以欢迎更好的答案或任何批评。

EN

回答 1

Stack Overflow用户

发布于 2016-07-19 22:38:48

Steve's answer on another question中,我使用了大部分代码来创建一个函数,以完成对匹配代码末尾的[..]通配符的支持。

代码语言:javascript
复制
CREATE FUNCTION CalculateMatchWeight 
(
    -- Add the parameters for the function here
    @MatchCode varchar(100)
)
RETURNS smallint
AS
BEGIN
    -- Declare the return variable here
    DECLARE @Result smallint = 0;

    -- Add the T-SQL statements to compute the return value here
    DECLARE @Pos int = 1, @N0 int = ascii('0'), @N9 int = ascii('9'), @AA int = ascii('A'), @AZ int = ascii('Z'), @Wild int = ascii('%'), @Range int = ascii('[');
    DECLARE @Asc int;
    DECLARE @WorkingString varchar(100) = upper(@MatchCode)

    WHILE @Pos <= LEN(@WorkingString)
    BEGIN
        SET @Asc = ascii(substring(@WorkingString, @Pos, 1));

        If ((@Asc between @N0 and @N9) or (@Asc between @AA and @AZ))
            SET @Result = @Result + 2;

        ELSE
        BEGIN
            -- Check wildcard matching, update value according to match strength, and stop calculating further.
            -- TODO: In the future we may wish to have match codes with wildcards not just at the end; try to figure out a mechanism to calculating that case.
            IF (@Asc = @Range)
            BEGIN
                SET @Result = @Result + 2;
                SET @Pos = 100;
            END
            IF (@Asc = @Wild)
            BEGIN
                SET @Result = @Result + 1;
                SET @Pos = 100;
            END
        END

        SET @Pos = @Pos + 1
    END

    -- Return the result of the function
    RETURN @Result
END

我已经检查过,这可以为我试图涵盖的当前情况生成所需的输出:

代码语言:javascript
复制
SELECT [dbo].[CalculateMatchWeight] ('12345');      -- Most precise (10)
SELECT [dbo].[CalculateMatchWeight] ('123[4-5]');   -- Middle       (8)
SELECT [dbo].[CalculateMatchWeight] ('123%');       -- Least        (7)

现在,我可以在INSERT/UPDATE的触发器中调用此函数来更新MATCH_WEIGHT

代码语言:javascript
复制
CREATE TRIGGER TRG_ENTRY_FORMAT_CalcMatchWeight
   ON  ENTRY_FORMAT
   AFTER INSERT,UPDATE
AS 
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for trigger here
    DECLARE @NewMatchWeight smallint = (select dbo.CalculateMatchWeight(inserted.MATCH_CODE) from inserted),
            @CurrentMatchWeight smallint = (select inserted.MATCH_WEIGHT from inserted);

    IF (@CurrentMatchWeight <> @NewMatchWeight)
    BEGIN
        UPDATE ENTRY_FORMAT
           SET MATCH_WEIGHT = @NewMatchWeight
          FROM inserted
         WHERE ENTRY_FORMAT.[MATCH_CODE] = inserted.[MATCH_CODE]
           AND ENTRY_FORMAT.[SEQUENCE] = inserted.[SEQUENCE]
    END
END
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38442835

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档