我不知道你为什么认为拆分是个坏主意。您可以创建一个相对高效的内联 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)