0

我昨天遇到了这个问题,以为我已经解决了,但我错了。出于此脚本的目的,我需要将变量放在带有分隔符的字符串中(这是因为最终用户将在帐户标题中搜索术语)。

例如,当标题中包含“水”或“食物”时,最终用户想要搜索。它们不必在同一个标​​题中。结果可能会返回“世界之水”和“深思熟虑”。

我知道我可以使用几个 AND 和 OR 语句轻松编写此代码

 SELECT ...
 FROM ...
 WHERE 1=1
 and (rpt_title LIKE '%Food%' 
 or rpt_title LIKE '%Water%')

该变量将只采用一个参数,但作为一个字符串。(即='食物|水')。我已经有一个函数,它将接受一个字符分隔的字符串并将其转换为多个变量。我不认为这是解决方案。我想我需要使用 substring 和 charindex 来定位分隔符( a | 在这种情况下,因为它很可能不在标题中),然后将其转换为 OR 语句。

有什么想法或建议吗?

编辑:最终结果将是输入变量的能力(例如 - rpt_title LIKE '%'+@title+'%')

4

3 回答 3

1

我不知道你为什么认为拆分是个坏主意。您可以创建一个相对高效的内联 TVF 并与之结合,例如假设您有一个 Numbers 表:

CREATE FUNCTION dbo.SplitStrings_Numbers
(
   @List       NVARCHAR(MAX),
   @Delimiter  NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
   RETURN
   (
       SELECT Item = SUBSTRING(@List, Number, 
         CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number)
       FROM dbo.Numbers
       WHERE Number <= CONVERT(INT, LEN(@List))
         AND SUBSTRING(@Delimiter + @List, Number, LEN(@Delimiter)) = @Delimiter
   );
GO

(对于绝对最有效的方法,例如 CLR,请参阅http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings

现在你可以说:

SELECT t.rpt_title
  FROM dbo.table_name AS t
  INNER JOIN dbo.SplitStrings_Numbers(@Input, '|') AS x
  ON t.rpt_title LIKE '%' + x.Item + '%'
  GROUP BY t.rpt_title;

另一个想法是不要像一开始那样使用列表foo|bar|splunge,而是使用 TVP。首先创建一个表类型:

CREATE TYPE dbo.TitleMatches
(
  Pattern NVARCHAR(64)
);
GO

然后是使用它的存储过程:

CREATE PROCEDURE dbo.Whatever
  @matches dbo.TitleMatches READONLY
AS
BEGIN
  SET NOCOUNT ON;

  SELECT t.rpt_title
    FROM dbo.table_name AS t
    INNER JOIN @matches AS m
    ON t.rpt_title LIKE '%' + m.Pattern + '%'
    GROUP BY t.rpt_title;
END
GO

然后你只需要传入你的 DataTable 或任何包含潜在匹配列表的结构,例如在 C# 中,这可能看起来像:

DataTable DataTableName = new DataTable();

// ... populate data table here

SqlCommand cmd = new SqlCommand("dbo.Whatever", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvp = cmd.Parameters.AddWithValue("@matches", DataTableName);
tvp.SqlDbType = SqlDbType.Structured;

// ... execute, consume results, etc.

(有关此的更多详细信息,请访问 http://www.sqlperformance.com/2012/08/t-sql-queries/splitting-strings-now-with-less-t-sql

于 2013-03-27T13:36:11.167 回答
0

听起来您需要使用动态 tsql,如下所示。不幸的是,我读过很多次,它使用起来效率不高,因为它不能由服务器预编译,并且每次运行时都必须在运行时进行优化,这比你这样做的方式要慢。但是,我认为这应该可以完成您的要求。要运行它,请使用 proc_DelimitedQuery 'aaa|bbb|etc' 调用它

create PROCEDURE [dbo].[proc_DelimitedQuery]

@delimitedString varchar(100)
as

DECLARE @delimiter int
declare @pos int
DECLARE @item varchar(500)
Declare @criteria varchar(5000)

set @criteria = '(rpt_title like ''%'

set @pos=1

--find the first delimiter
SET @delimiter = CHARINDEX('|', @delimitedString, @pos)

WHILE @delimiter<>0
BEGIN
    set @item=substring(@delimitedString, @pos, @delimiter-@pos)
    set @criteria = @criteria + @item + '%'' or rpt_title like ''%'

    --Find the next delimiter
    set @pos=@delimiter+1

    if charindex('|', @delimitedString, @pos)=0
    begin

        set @pos=@delimiter+1
        set @item=substring(@delimitedString, @pos, datalength(@delimitedString)-@delimiter)
        set @criteria = @criteria + @item + '%'')'      
        set @delimiter=0
    end
    else
    begin
        set @delimiter=charindex('|', @delimitedString, @pos)
    end


END

declare @sql varchar(500)
set @sql='select * from MyTable where 1=1 and ' + @criteria

    --change the next line to select @sql if you want to examine the sql statement
EXECUTE(@sql)
GO
于 2013-03-27T14:45:13.030 回答
0

好吧,这有点脏,但它起作用了。原谅我,我有一段时间没有做过 TSQL。

DECLARE @delim CHAR, @search NVARCHAR(100)
set @delim = '|'
set @search = 'world|food'

DECLARE @tblSearch TABLE(
string NVARCHAR(100)
)

DECLARE @tmpStr NVARCHAR(100)
WHILE (@search <> '')
BEGIN
    IF (CHARINDEX(@delim, @search) = 0)
        BEGIN
            INSERT INTO @tblSearch(string) VALUES('%' + @search + '%')
            SET @search = ''
        END
    ELSE
        BEGIN
            INSERT INTO @tblSearch(string)
            SELECT '%' + SUBSTRING(@search, 0, CHARINDEX(@delim, @search)) + '%'
            SET @search = SUBSTRING(@search, CHARINDEX(@delim, @search) + 1, LEN(@search))
        END
END

SELECT ...
FROM ... as m
INNER JOIN @tblSearch as s ON m.rpt_title like s.string
于 2013-03-27T14:18:12.373 回答