将分隔的字符串传递给存储过程以搜索数据库

时间:2010-05-19 14:44:59

标签: sql sql-server sql-server-2005 tsql sql-server-2000

如何将空格或逗号分隔的字符串传递给存储过程和过滤结果? 我正在尝试做类似的事情 -

Parameter      Value
--------------------------
@keywords      key1 key2 key3

然后是我想要的存储过程

  1. 查找包含第一个或最后一个的所有记录 名称如key1
  2. 使用第一个或最后一个过滤步骤1 名称如key2
  3. 过滤第2步,第一个或最后一个名称,如键3
  4. 另一个例子:

    col1    |       col2        | col3
    ------------------------------------------------------------------------
    hello xyz   |   abc is my last name | and i'm a developer
    hello xyz   |       null        | and i'm a developer
    

    如果我搜索任何后续内容,它应该返回每个?

    1. “xyz developer”返回2行

    2. “xyz abc”返回1行

    3. “abc developer”返回1行

    4. “hello”返回2行

    5. “hello developer”返回2行

    6. “xyz”返回2行

2 个答案:

答案 0 :(得分:2)

由于您无法使用表参数(不在SQL Server 2008上),请尝试传入CSV sting并让存储过程将其拆分为多行。

在SQL Server中分割字符串的方法有很多种。本文涵盖几乎所有方法的PRO和CON:

"Arrays and Lists in SQL Server 2005 and Beyond, When Table Value Parameters Do Not Cut it" by Erland Sommarskog

您需要创建拆分功能。这就是如何使用拆分功能:

SELECT
    *
    FROM YourTable                               y
    INNER JOIN dbo.yourSplitFunction(@Parameter) s ON y.ID=s.Value

I prefer the number table approach to split a string in TSQL但是有很多方法可以在SQL Server中拆分字符串,请参阅上一个链接,该链接解释了每个链接的PRO和CON。

要使Numbers Table方法起作用,您需要进行一次性表设置,这将创建一个包含1到10,000行的表Numbers

SELECT TOP 10000 IDENTITY(int,1,1) AS Number
    INTO Numbers
    FROM sys.objects s1
    CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)

设置Numbers表后,创建此拆分功能:

CREATE FUNCTION [dbo].[FN_ListToTable]
(
     @SplitOn  char(1)      --REQUIRED, the character to split the @List string on
    ,@List     varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN 
(   ----------------
    --SINGLE QUERY-- --this will not return empty rows
    ----------------
    SELECT
        ListValue
        FROM (SELECT
                  LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue
                  FROM (
                           SELECT @SplitOn + @List + @SplitOn AS List2
                       ) AS dt
                      INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
                  WHERE SUBSTRING(List2, number, 1) = @SplitOn
             ) dt2
        WHERE ListValue IS NOT NULL AND ListValue!=''
);
GO 

现在,您可以轻松地将空格分隔的字符串拆分为表格并加入其中或使用它,但是您需要此代码基于OP最新的问题编辑:

CREATE TABLE YourTable (PK int, col1 varchar(20), col2 varchar(20), col3 varchar(20))
--data from question
INSERT INTO YourTable VALUES (1,'hello xyz','abc is my last name','and i''m a developer')
INSERT INTO YourTable VALUES (2,'hello xyz',null,'and i''m a developer')

CREATE PROCEDURE YourProcedure
(
    @keywords   varchar(1000)
)
AS

SELECT
    @keywords AS KeyWords,y.* 
    FROM (SELECT
              t.PK
              FROM dbo.FN_ListToTable(' ',@keywords) dt
                  INNER JOIN YourTable             t ON  t.col1 LIKE '%'+dt.ListValue+'%' OR t.col2 LIKE '%'+dt.ListValue+'%' OR t.col3 LIKE '%'+dt.ListValue+'%'
              GROUP BY t.PK
              HAVING COUNT(t.PK)=(SELECT COUNT(*) AS CountOf FROM dbo.FN_ListToTable(' ',@keywords))
         ) dt
        INNER JOIN YourTable y ON dt.PK=y.PK
GO

--from question   
EXEC YourProcedure 'xyz developer'-- returns 2 rows
EXEC YourProcedure 'xyz abc'-- returns 1 row
EXEC YourProcedure 'abc developer'-- returns 1 row
EXEC YourProcedure 'hello'--  returns 2 rows
EXEC YourProcedure 'hello developer'--  returns 2 rows
EXEC YourProcedure 'xyz'-- returns 2 rows

输出:

KeyWords       PK    col1       col2                 col3
-------------- ----- ---------- -------------------- --------------------
xyz developer  1     hello xyz  abc is my last name  and i'm a developer
xyz developer  2     hello xyz  NULL                 and i'm a developer

(2 row(s) affected)

KeyWords       PK    col1       col2                 col3
-------------- ----- ---------- -------------------- --------------------
xyz abc        1     hello xyz  abc is my last name  and i'm a developer

(1 row(s) affected)

KeyWords       PK    col1       col2                 col3
-------------- ----- ---------- -------------------- --------------------
abc developer  1     hello xyz  abc is my last name  and i'm a developer

(1 row(s) affected)

KeyWords       PK    col1       col2                 col3
-------------- ----- ---------- -------------------- --------------------
hello          1     hello xyz  abc is my last name  and i'm a developer
hello          2     hello xyz  NULL                 and i'm a developer

(2 row(s) affected)

KeyWords        PK    col1       col2                 col3
--------------- ----- ---------- -------------------- --------------------
hello developer 1     hello xyz  abc is my last name  and i'm a developer
hello developer 2     hello xyz  NULL                 and i'm a developer

(2 row(s) affected)

KeyWords       PK    col1       col2                 col3
-------------- ----- ---------- -------------------- --------------------
xyz            1     hello xyz  abc is my last name  and i'm a developer
xyz            2     hello xyz  NULL                 and i'm a developer

(2 row(s) affected)

答案 1 :(得分:1)

您可以尝试以下方式:

select firstname, lastname from @test t1
inner join persondata t on t.firstname like '%' + t1.x + '%' or t.lastname like '%' + t1.x + '%'
group by firstname, lastname
having count(distinct x) = (select count(*) from @test)

其中@test是包含拆分结果的表格。如果persondata中有很多列,您可能只想从此查询返回一个ID,并将其用作实际返回数据的子查询,因此您不必按如此多的列进行分组。

编辑:您也可以使用游标和另一个临时表/表变量,但我对SP中的游标有过敏反应。