admin

根据业务逻辑获取第一个合并结果

sql

我的表T1看起来像这样:

ID  VALUE
----------
1   1
2   32
3   6
4   42
5   8
6   62
7   43
8   34

我的第二个T2看起来像这样:

ID  DEFINITION
---------------
1   A|B|C     
2   er|All|All|B  
3   All|All|All   
4   All|bela|All 
5   All|All|All|G
6   A|All|All
7   All|B|All 
8   Av|All|All|G

该表后面的业务逻辑是,传递字符串时,应应用最具体的DEFINITION,并应检索各自的值。“全部”可以解释为“%”。“ |”
只是一个分隔符,它定义了您实际传递的值。每个字符串都可以是任何东西…

例如,如果我的定义为’X | B | Z’->值应为7。如果我具有’A | B |
C’->值应为1(不是1,6,7)-仅应该从右边的休假水平开始检索最具体的结果。

我已经问过一个非常类似的问题(SQL
Server:获得第一个联接值
),并获得了这个出色的解决方案Gordon
Linnof,但不幸的是它涵盖的范围不止3个维度。我现在在该表中有新的值,该值可以有更多的子字符串。

有什么方法可以动态地获取正确的值?

select top (1) t.*
from t
where @str like replace(t.definition, 'All', '%')
order by (case when t.definition like '%All%All%All%' then 3
               when t.definition like '%All%All%' then 2
               when t.definition like '%All%' then 1
               else 0
          end) asc;

编辑:我需要为这个问题添加更多细节,因为Habo添加了一些有效的注释:字符串值表示字母数字ID的egT34或ABC78,可以是varchar(255)。

您拥有的所有值越少,则它越具体-这是一个正确的选择。


阅读 177

收藏
2021-07-01

共1个答案

admin

这应该可以解决问题:

Declare @str VARCHAR(100) = 'A|B|C';

DECLARE
@Test TABLE
    (
         Id         INT
        ,Definition VARCHAR(100)
    )

INSERT INTO
    @Test (Id, Definition)
VALUES
     (1, 'A|B|C')
    ,(2, 'er|All|All|B')
    ,(3, 'All|All|All')
    ,(4, 'All|bela|All')
    ,(5, 'All|All|All|G')
    ,(6, 'A|All|All')
    ,(7, 'All|B|All')
    ,(8, 'Av|All|All|G')
;

---------------------------------------------------------------------------

WITH Tester AS
(
    SELECT
         Id
        ,Definition
        ,(LEN(Definition) - LEN(REPLACE(Definition, 'All', ''))) / LEN('All') AS numAlls
        ,REPLACE(Definition, 'All', '%') AS Mask
    FROM
        @Test
)

SELECT TOP 1
     Id
    ,Definition
FROM
    Tester
WHERE
    @str LIKE Mask
ORDER BY
     numAlls

这里的主键是列:

(LEN(Definition) - LEN(REPLACE(Definition, 'All', ''))) / LEN('All') AS numAlls

基本上,我接受您给出的顺序的想法,并通过简单地计算单词All在定义中出现的次数而不是显式创建多个语句来使其变得更通用。

希望有道理/能解决问题!


编辑:

为了完整起见并解决@HABO在评论中提出的真正有效的观点,即上述解决方案在单词All出现在字符串中的任何时间都将匹配,即使它是另一个语句/单词的一部分,下面的解决方案也是健壮/保证仅匹配以下情况All

WITH Tester AS
(
    SELECT
         Id
        ,Definition
        ,(LEN('|' + Definition + '|') - LEN(REPLACE('|' + Definition + '|', '|All|', ''))) / LEN('|All|') AS numAlls
        ,REPLACE('|' + Definition + '|', '|All|', '|%|') AS Mask
    FROM
        @Test
)

SELECT TOP 1
     Id
    ,Definition
FROM
    Tester
WHERE
    '|' + @str + '|' LIKE Mask
ORDER BY
     numAlls

基本上,您可以Definition使用分隔符(|)将其括起来,以确保Definition开头和结尾的每个部分都以分隔符(开始/结束值并非如此),然后我们就可以进行全文搜索|All|

希望这对为什么这是一个更加健壮的解决方案有意义。

2021-07-01