逗号分隔列表上的T-SQL LIKE条件

时间:2012-07-28 22:42:39

标签: sql tsql sql-server-ce

是否可以在T-SQL中编写LIKE条件,以匹配包含通配符到字符串的逗号分隔列表。让我用一个例子进一步解释:

假设您在字段中有以下命令分隔的网址列表:

'/, /news/%, /about/'

现在,这里有一些字符串示例,我想与上面的字符串匹配:

  1. ' /'
  2. ' /消息/'
  3. ' /消息/ 2 /'
  4. ' /左右/'
  5. 这里有一些不匹配的字符串:

    1. ' /接触/'
    2. ' /约/ ME /'
    3. 我过去通过编写分割函数然后在每个函数上做了类似的事情来实现这一点。但是,我试图让我的查询在不支持函数的SQL Server CE中工作。

      如果您想知道我是如何使用拆分功能实现的:

      SELECT Widgets.Id 
      FROM Widgets 
      WHERE (SELECT COUNT(*) FROM [dbo].[Split](Urls, ',') WHERE @Input LIKE Data) > 0
      

      以下是拆分功能:

      CREATE FUNCTION [dbo].[Split]
      (    
          @RowData NVARCHAR(MAX),
          @Separator NVARCHAR(MAX)
      )
      RETURNS @RtnValue TABLE 
      (
          [Id] INT IDENTITY(1,1),
          [Data] NVARCHAR(MAX)
      ) 
      AS
      BEGIN 
          DECLARE @Iterator INT
          SET @Iterator = 1
      
          DECLARE @FoundIndex INT
          SET @FoundIndex = CHARINDEX(@Separator, @RowData)
      
          WHILE (@FoundIndex > 0)
          BEGIN
              INSERT INTO @RtnValue ([Data])
              SELECT Data = LTRIM(RTRIM(SUBSTRING(@RowData, 1, @FoundIndex - 1)))
      
              SET @RowData = SUBSTRING(@RowData, @FoundIndex + DATALENGTH(@Separator) / 2, LEN(@RowData))
              SET @Iterator = @Iterator + 1
              SET @FoundIndex = CHARINDEX(@Separator, @RowData)
          END
      
          INSERT INTO @RtnValue ([Data])
          SELECT Data = LTRIM(RTRIM(@RowData))
      
          RETURN
      END
      

      如果有人可以提供帮助,我会很感激。感谢

2 个答案:

答案 0 :(得分:2)

我可以想到几个选项:

  1. 使用会话密钥表:删除与当前spid匹配的行,使用当前spid插入所需的行,从SP中的表中读取,从表中删除(再次)。

  2. 让您的客户提交一个包含许多OR ... LIKE ...子句的查询。

  3. 编写一个与您的函数完全相同的SP并返回一个记录集。 INSERT YourTable EXEC SP @Strings已经完成了!

  4. 在分割字符串的派生表方法中使用numbers-table-charindex-into-string。

  5. 示例

    让我以一个结合思想#3和#4的例子为你充实。当然,您的功能代码也可以调整。

    构建单独的Numbers表。这是示例创建脚本:

    --Numbers Table with 8192 elements (keeping it small for CE)
    CREATE TABLE Numbers (
       N smallint NOT NULL CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED
    );
    INSERT Numbers VALUES (1);
    WHILE @@RowCount < 4096
       INSERT Numbers SELECT N + (SELECT Max(N) FROM Numbers) FROM Numbers;
    

    SP:

    CREATE PROCEDURE dbo.StringSplitRowset
       @String varchar(8000)
    AS
    SELECT Substring(@String, l.StartPos, l.Chars) Item
    FROM (
       SELECT
          S.StartPos,
          IsNull(NullIf(CharIndex(',', @String, S.StartPos), 0) - S.StartPos, 8000)
       FROM (
          SELECT 1 UNION ALL
          SELECT N.N + 1 FROM Numbers N WHERE Substring(@String, N.N, 1) = ','
       ) S (StartPos)
    ) L (StartPos, Chars);
    

    用法,很容易就像馅饼一样:

    DECLARE @String varchar(8000);
    SET @String = 'abc,def,ghi,jkl';
    CREATE TABLE #Split (S varchar(8000));
    INSERT #Split EXEC dbo.StringSplitRowset @String;
    SELECT * FROM #Split;
    

    结果:

    abc
    def
    ghi
    jkl
    

    最后,如果您不想构建数字表,则可以使用此SP。我想你会发现这两个SP中的一个对你来说效果很好。还有其他字符串拆分实现也可以。

    ALTER PROCEDURE dbo.StringSplitRowset
      @String varchar(8000)
    AS
    SELECT Substring(@String, l.StartPos, l.Chars) Item
    FROM (
       SELECT
          S.StartPos,
          IsNull(NullIf(CharIndex(',', @String, S.StartPos), 0) - S.StartPos, 8000)
       FROM (
          SELECT 1 UNION ALL
          SELECT N.N + 1
          FROM (
             SELECT A.A * 4096 + B.B * 1024 + C.C * 256 + D.D * 64 + E.E * 16 + F.F * 4 + G.G N
             FROM
                (SELECT 0 UNION ALL SELECT 1) A (A),
                (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) G (G),
                (SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) F (F),
                (SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) E (E),
                (SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) D (D),
                (SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) C (C),
                (SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) B (B)
          ) N (N)
          WHERE Substring(@String, N.N, 1) = ','
       ) S (StartPos)
    ) L (StartPos, Chars)
    

    任何认真理解分解字符串不同方式的性能影响的SQL编写者都应该看Aaron Bertrand's blog post on splitting strings

    此外,任何严肃的SQL Server数据库学生都应该看到Erland Sommarskog's How to Share Data between Stored Procedures

答案 1 :(得分:0)

SQL Server CE是否允许您使用XML功能进行拆分并使用CROSS APPLY?如果是这样,你可以这样做:

SELECT DISTINCT T1.id
FROM (
      SELECT id,  CAST(('<X>'+
                        REPLACE(REPLACE(urls,' ',''),',','</X><X>')+
                        '</X>'
                       ) AS xml
                      ) as URLsXML
      FROM dbo.Widgets
     ) AS T1
CROSS APPLY(
            SELECT N.value('.', 'varchar(50)') AS URLPattern 
            FROM URLsXML.nodes('X') AS S(N)
           ) AS T2
WHERE @Input LIKE T2.URLPattern

更新:我刚检查过。看起来SQL Server CE不支持XML数据类型或CROSS APPLY。 我认为你将不得不填充另一个带有ID和模式的表来加入。