如果IN子句没有值,如何返回所有行?

Pau*_*aul 3 t-sql performance sql-server-2005 in-clause sql-like

以下是示例查询.

CREATE PROCEDURE GetModel
(
    @brandids varchar(100), -- brandid="1,2,3"
    @bodystyleid varchar(100) -- bodystyleid="1,2,3"

)
AS
   select * from model
   where brandid in (@brandids) -- use a UDF to return table for comma delimited string
   and bodystyleid in (@bodystyleid)
Run Code Online (Sandbox Code Playgroud)

我的要求是,如果@brandids@bodystyleid为空,查询应返回该条件的所有行.

请指导我怎么做?还建议如何编写此查询以优化性能.

Aar*_*and 5

无论如何你都需要动态SQL或拆分功能,因为IN ('1,2,3')它不一样IN (1,2,3).

分割功能:

CREATE FUNCTION dbo.SplitInts
(
   @List       VARCHAR(MAX),
   @Delimiter  CHAR(1)
)
RETURNS TABLE
AS
   RETURN ( SELECT Item = CONVERT(INT, Item) FROM ( 
     SELECT Item = x.i.value('(./text())[1]', 'int') FROM ( 
       SELECT [XML] = CONVERT(XML, '<i>' + REPLACE(@List, @Delimiter, '</i><i>') 
       + '</i>').query('.') ) AS a CROSS APPLY [XML].nodes('i') AS x(i)) AS y
     WHERE Item IS NOT NULL
   );
Run Code Online (Sandbox Code Playgroud)

代码变成如下:

SELECT m.col1, m.col2 FROM dbo.model AS m
LEFT OUTER JOIN dbo.SplitInts(NULLIF(@brandids, ''), ',') AS br
ON m.brandid = COALESCE(br.Item, m.brandid)
LEFT OUTER JOIN dbo.SplitInts(NULLIF(@bodystyleid, ''), ',') AS bs
ON m.bodystyleid = COALESCE(bs.Item, m.bodystyleid)
WHERE (NULLIF(@brandids, '') IS NULL OR br.Item IS NOT NULL)
AND (NULLIF(@bodystyleid, '') IS NULL OR bs.Item IS NOT NULL);
Run Code Online (Sandbox Code Playgroud)

(注意我在这里添加了很多NULLIF处理...如果这些参数没有值,你应该传递NULL,而不是"空白".)

由于参数嗅探,动态SQL导致错误计划的可能性要小得多:

DECLARE @sql NVARCHAR(MAX);

SET @sql = N'SELECT columns FROM dbo.model
WHERE 1 = 1 '
+ COALESCE(' AND brandid IN (' + @brandids + ')', '')
+ COALESCE(' AND bodystyleid IN (' + @bodystyleid + ')', '');

EXEC sp_executesql @sql;
Run Code Online (Sandbox Code Playgroud)

当然,正如@JamieCee指出的那样,动态SQL 可能容易受到注入攻击,因为您会发现是否在任何地方搜索动态SQL.因此,如果您不信任您的输入,您将需要防范潜在的注入攻击.就像您在应用程序代码中组装临时SQL一样.

当您迁移到SQL Server 2008或更高版本时,您应该查看表值参数(此处为示例).

  • @JamieSee我也看到开发团队花了很多时间来保护他们的代码免受恶意用户的攻击,以至于他们将性能提升到了厕所.函数,合并等等为执行计划增加了很多波动性,动态SQL很容易保护,以防止未经过处理的输入.如果您认为我的评论不充分,请随时添加更全面的答案. (2认同)