【问题标题】:T-SQL LIKE condition on comma-separated list逗号分隔列表上的 T-SQL LIKE 条件
【发布时间】:2012-07-28 22:42:38
【问题描述】:

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

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

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

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

  1. '/'
  2. '/新闻/'
  3. '/news/2/'
  4. '/关于/'

还有一些不匹配的字符串:

  1. '/contact/'
  2. '/about/me/'

我在过去通过编写一个拆分函数然后对每个函数都执行类似操作来实现这一点。但是我试图让我的查询在不支持函数的 SQL Server CE 中工作。

如果你想知道我是如何使用 split 函数实现它的:

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

如果有人可以提供帮助,我将不胜感激。谢谢

【问题讨论】:

  • 您的问题的答案是“否”。您可能会调查正则表达式。或者,如果您将“逗号分隔列表”保留为单独的表格,每行一个项目,那么您可以将 like 用于连接。

标签: sql tsql sql-server-ce


【解决方案1】:

我能想到几个选项:

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

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

  3. 编写一个与您的函数执行相同操作并返回记录集的 SP。 INSERT YourTable EXEC SP @Strings,你就完成了!

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

示例

让我通过结合想法#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

【讨论】:

    【解决方案2】:

    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 和模式填充另一个表才能加入。

    【讨论】:

      猜你喜欢
      • 2014-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-19
      • 1970-01-01
      • 1970-01-01
      • 2018-08-07
      • 2016-10-24
      相关资源
      最近更新 更多