SQL Server存储过程中的参数化WHERE子句

时间:2016-04-25 08:00:42

标签: sql sql-server stored-procedures

我有一个存储过程来获取发票的详细信息

有些情况下,我只通过发送InvoiceID来获取发票清单 但在其他一些场合,我需要根据用户提供的搜索字段获取发票清单。为此,我将所有字段发送到存储过程并使用以下参数。我只包括2列,但还有更多。

SELECT * FROM INVOICES I
    WHERE 
    (@InvoiceNumber is null or  I.InvoiceNumber =  @InvoiceNumber)
    and
    (@PONo is null or I.PONo = @PONo)

有没有办法将WHERE子句的条件作为一个参数发送?

3 个答案:

答案 0 :(得分:2)

是的,动态SQL是可行的,但我强烈反对这样做。

SELECT * FROM tbl WHERE @condition

  

如果您正在考虑编写程序

CREATE PROCEDURE search_sp @condition varchar(8000) AS
   SELECT * FROM tbl WHERE @condition
     

忘了它。如果您这样做,您还没有完成使用存储过程的过渡,而您仍在组装您的   客户端中的SQL代码。

它还会打开你的SQL注入攻击应用程序。

答案 1 :(得分:1)

您可以使用自定义类型将表作为参数https://msdn.microsoft.com/pl-pl/library/bb510489(v=sql.110).aspx传递,也可以使用默认参数

答案 2 :(得分:0)

If you're using SQL Server 2016 or similar (check by calling select compatibility_level, name from sys.databases and seeing that your DB is 130 or higher) then you can use the string_split builtin function.

I found it works best like this (spread out for clarity)

CREATE PROCEDURE [dbo].[GetInvoices]
  @InvoiceNumber int = NULL
  @PONo nvarchar(1024) = NULL
AS
SELECT * from [Invoices] AS [i] 
WHERE
  i.InvoiceNumber = ISNULL(@InvoiceNunber, i.InvoiceNunber)
  AND CASE 
      WHEN @PONo is null 
      THEN 1 
      ELSE (CASE 
           WHEN i.PONo IN (select value from string_split(@PONo, ',')) 
           THEN 1 
           ELSE 0 
           END) 
      END 
      = 1

So if you pass in a null to either parameter it gets translated as where x = x which is always true, and if you pass in a CSV value, it selects it from a split table of values that, if present, results in the where clause being where 1=1, which is true or 0=1 if the value is not present in the input list.

So here you can pass in an invoice number, or PO number, or both, or neither and it should return what you expect.