Передача строки с разделителями в хранимую процедуру для поиска в базе данных - PullRequest
2 голосов
/ 19 мая 2010

Как передать строку, разделенную пробелом или запятой, в хранимую процедуру и отфильтровать результат? Я пытаюсь сделать что-то вроде -

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

Затем сохраняется процедура, которую я хочу сначала

  1. найти все записи с первым или последним имя как key1
  2. фильтр шаг 1 с первым или последним имя как key2
  3. фильтр шаг 2 с именем или фамилией, например ключ 3

Другой пример:

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. "привет" возвращает 2 строки

  5. «Привет, разработчик» возвращает 2 строки

  6. "xyz" возвращает 2 строки

Ответы [ 2 ]

2 голосов
/ 19 мая 2010

Поскольку вы не можете использовать параметр таблицы (не в SQL Server 2008), попробуйте передать строку CSV, и хранимая процедура разделит его на строки.

Есть много способов разбить строку в SQL Server. В этой статье рассматриваются плюсы и минусы практически каждого метода:

"Массивы и списки в SQL Server 2005 и более поздних версиях, когда параметры табличных значений не обрезают его", Эрланд Соммарског

Вам необходимо создать функцию разделения. Вот как можно использовать функцию разделения:

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

Я предпочитаю подход с использованием таблиц чисел для разделения строки в TSQL , но существует множество способов разделения строк в SQL Server, см. Предыдущую ссылку, которая объясняет за и против каждого из них.

Чтобы метод таблицы чисел сработал, необходимо выполнить настройку единой таблицы, которая создаст таблицу Numbers, содержащую строки от 1 до 10000:

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 

Теперь вы можете легко разбить строку, разделенную пробелом, на таблицу и присоединиться к ней или использовать ее так, как вам нужно. Эти коды основаны на последнем редактировании вопроса ОП:

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 голос
/ 19 мая 2010

Вы можете попробовать что-то вроде:

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 - таблица с результатами вашего сплита. Если у вас есть много столбцов в персонализированных данных, вы можете просто вернуть идентификатор из этого запроса и использовать его как подзапрос для того, который фактически возвращает данные, так что вам не нужно группировать по стольким столбцам. *

Редактировать: вы также можете использовать курсор и другую временную таблицу / переменную таблицы, но у меня есть своего рода аллергическая реакция на курсоры в SP.

...