要在字符串值中搜索的SQL函数

时间:2016-12-09 20:19:01

标签: sql-server

我想在sql server上创建函数来检查字符串值。

传递给两个参数:第一个原始'12.33.44.65.22',第二个'44.22'并返回

如果在true中找到parameter2,则

original parameter 例如:

call fun1('22.34.56.78' , '23.24')  -- return false 
call fun1('22.34.56.78' , '23.24') -- return false 
call fun1('22.34.56.78.43.76' , '22.12') -- return false , because should be both exists 
call fun1('22.34.56.78' , '22.56') -- return true 
call fun1('21.34.56.54' , '21.56') -- return true 
call fun1('21.34.56.54' , '34.56') -- return true 
call fun1('22.34.56.78' , '34.55.35') -- return false

感谢。

4 个答案:

答案 0 :(得分:1)

根据更新的问题,这不是答案。您希望确认分隔符值字符串中的所有值都存在于另一个分隔值的字符串中,在这种情况下,分隔符为“。”

select 
  case when charindex('44.22','12.33.44.65.22')>0 then 'true' 
    else 'false' 
    end

更新:如果搜索字符串始终采用该格式,则可以使用:

create function dbo.func1 (@StringToFind nvarchar(128), @StringToSearch nvarchar(128))
returns nvarchar(5) as
begin
  return case 
          when charindex(left(@StringToFind,charindex('.',@StringToFind)-1),@StringToSearch)>0 
           and charindex(right(@StringToFind,charindex('.',reverse(@StringToFind))-1),@StringToSearch)>0 
          then 'true' 
          else 'false' 
          end;
end
go

select dbo.func1('44.22','12.33.44.65.22')

答案 1 :(得分:0)

Declare @YourTable table (TheString varchar(100), FindString varchar(100));
Insert Into @YourTable values
 ('22.34.56.78','23.24')       -- return false 
,('22.34.56.78.43.76','22.12') -- return false , because should be both exists 
,('22.34.56.78','22.56')       -- return true 
,('21.34.56.54','21.56')       -- return true 
,('21.34.56.54','34.56')       -- return true 
,('22.34.56.78','34.55.35');

Select *
      ,InString = [dbo].[udf_InString](TheString,FindString)
From @YourTable

返回

TheString           FindString  InString
22.34.56.78         23.24       false
22.34.56.78.43.76   22.12       false
22.34.56.78         22.56       true
21.34.56.54         21.56       true
21.34.56.54         34.56       true
22.34.56.78         34.55.35    false

UDF

CREATE FUNCTION [dbo].[udf_InString](@String varchar(max),@Search varchar(max))
Returns varchar(25)
Begin
    Declare @RetVal varchar(25)
    ;with cte as (
        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,'.','</x><x>')+'</x>' as xml).query('.')) as A 
        Cross Apply x.nodes('x') AS B(i)
    )
    Select @RetVal = case when count(*)>0 then 'true' else 'false' end
     From  cte A
     Join  cte B on (A.RetSeq+1=B.RetSeq or A.RetSeq+2=B.RetSeq)
     Where A.RetVal+'.'+B.RetVal = @Search
    Return @RetVal
End

答案 2 :(得分:0)

您可以这样尝试:

我首先使用XML技巧将分隔的字符串拆分为它们的部分(获取派生表)。 INNER JOIN将它们缩减为双方包含的部分。剩下的就是计算:如果公共元素的数量等于第2侧的总数,则所有元素都是常见的:

注意:任何没有共同元素的行都会被忽略。您可以对所有现有ID的LEFT JOIN列表使用DISTINCT来包含没有值交叉的行...

应该很容易从此创建一个功能。只需将两个字符串作为参数输入,并将TheStringCheckString替换为它们(并删除FROM @dummyTbl)。在这种情况下,空结果为false

DECLARE @dummyTbl TABLE(ID INT IDENTITY,TheString VARCHAR(100), CheckString VARCHAR(100));
INSERT INTO @dummyTbl VALUES
 ('22.34.56.78','23.24')  -- return false 
,('22.34.56.78.43.76','22.12') -- return false , because should be both exists 
,('22.34.56.78','22.56') -- return true 
,('21.34.56.54','21.56') -- return true 
,('21.34.56.54','34.56') -- return true 
,('22.34.56.78','34.55.35');

WITH casted AS
(
    SELECT ID
          ,CAST('<x>' + REPLACE(TheString,'.','</x><x>') + '</x>' AS XML) AS s1
          ,CAST('<x>' + REPLACE(CheckString,'.','</x><x>') + '</x>' AS XML) AS s2
    FROM @dummyTbl
)
,s1Tbl AS
(
    SELECT ID,x.value('.','int') Val 
    FROM casted
    CROSS APPLY s1.nodes('/x') AS A(x)
)
,s2Tbl AS
(
    SELECT ID,x.value('.','int') Val 
    FROM casted
    CROSS APPLY s2.nodes('/x') AS A(x)
)
SELECT s1Tbl.ID
      ,CASE WHEN COUNT(s1Tbl.ID)=(SELECT COUNT(x.ID) FROM s2Tbl AS x WHERE x.ID=s1Tbl.ID) THEN 'true' else 'false' END AS FullyIncluded
FROM s1Tbl
INNER JOIN s2Tbl ON s1Tbl.Val=s2Tbl.Val AND s1Tbl.ID=s2Tbl.ID
GROUP BY s1Tbl.ID

答案 3 :(得分:0)

这是一个使用XML来吐出字符串的函数和一个反连接,以查看是否所有内容都匹配。然后你可以简单地将它称为交叉应用,如下所示。

CREATE FUNCTION dbo.FindStringsInString(
    @String VARCHAR(MAX)
    ,@SearchString VARCHAR(MAX)
)
RETURNS BIt
AS
BEGIN
    IF (COALESCE(LEN(@String),0) = 0 OR COALESCE(LEN(@SearchString),0) = 0)
    BEGIN
       --either the String or the SearchString is Null or Empty
       RETURN 0
    END

    DECLARE @XMLString XML = CAST('<X>' + REPLACE(@String,'.','</X><X>') + '</X>' AS XML)
    DECLARE @XMLSearchString XML = CAST('<X>' + REPLACE(@SearchString,'.','</X><X>') + '</X>' AS XML)

    IF NOT EXISTS (
       SELECT 1
       FROM
          (
          SELECT
             n.value('.', 'varchar(MAX)') as S
          FROM
             @XMLSearchString.nodes('X') as t(n)) searchstring
          LEFT JOIN (
          SELECT
             n.value('.', 'varchar(MAX)') as S
          FROM
             @XMLString.nodes('X') as t(n)) string
          ON searchstring.S = string.S
       WHERE
          string.S IS NULL
    )
    BEGIN
       --All of the values in the Search StringMatch a Value in the String
       RETURN 1
    END

    --default if it hasn't returned by now it is false
    RETURN 0

END
GO

测试数据,我添加了NULL和&#39;&#39;案例和从功能中选择:

DECLARE @Table AS TABLE (String VARCHAR(100), SearchString VARCHAR(100))
INSERT INTO @Table VALUES
('22.34.56.78' , '23.24')  -- return false 
,('22.34.56.78' , '23.24') -- return false 
,('22.34.56.78.43.76' , '22.12') -- return false , because should be both exists 
,('22.34.56.78' , '22.56') -- return true 
,('21.34.56.54' , '21.56') -- return true 
,('21.34.56.54' , '34.56') -- return true 
,('22.34.56.78' , '34.55.35') -- return false
,('22.34.56.78' , NULL) -- return false
,('22.34.56.78' , '') -- return false
,(NULL , '34.55.35') -- return false
,('' , '34.55.35') -- return false

SELECT *
FROM
    @Table t
    CROSS APPLY (SELECT
       dbo.FindStringsInString(t.String, t.SearchString)) s(Match)