具有多个不同where子句的SQL Server存储过程动态SQL

问题描述 投票:0回答:1

输入CASE1 = wen @type为NULL->在@Start和@End之间c.Date_Redeemed之间-这应该执行

如果CASE2 = wen @ start,@ end为NULL-> WHERE c.Type=@type--应该执行情况3 = wen @value为null-> WHERE c.Date_Redeemed @Start AND @End AND c.Type=@type应该执行的位置

CASE4 = wen @marketclass为NULL->在@Start AND @End AND c.Type=@type AND c.ordervalue在@ price1和@ price2之间的c.Date_Redeemed中

VAR = @ type,@ start,@ price1,@ marketclass,如果var的实数为NULL动态地必须执行条件的其他输入,如输入的diff组合出现

WHERE
   (c.Type = @type AND o.Date_of_Purchase BETWEEN @start AND @end) OR
   (@start IS NULL AND c.Type = @type) OR
   (@type IS NULL and o.Date_of_Purchase BETWEEN @start AND @end) OR
   (@start IS NULL AND @type IS NULL)
  • 如果同时提供,则仅返回类型和日期匹配的行,
  • 如果未提供类型,则使用日期,
  • 如果使用未提供日期的类型并且
  • 如果未提供任何内容,则返回所有行。要不返回任何行,请删除最后一个谓词

代码:

CREATE PROCEDURE dbo.sample 
    @start DATE, @end DATE, 
    @type VARCHAR(5),
    @price1 MONEY, @price2 MONEY
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @SQL VARCHAR(MAX)

    SET @SQL= 'SELECT DISTINCT o.O_Id,o.Sale_Price,o.Order_Line_Id,Private_Band,c.Date_of_Purchase,c.Date_Redeemed,c.Credit_Memo,c.Credit_Memo_Created_Date,c.Credit_Memo_Approved_Date,
    c.Type,c.Points_Issued,o.Date_of_Purchase FROM Order_Details o ,Transaction_Historys c WHERE -1='-1''
    IF @type IS NOT NULL AND @type <> 0            
    SET @SQL = @SQL+ 'c.Type = @type'
    ELSE
    IF @start IS NOT NULL AND @start <> 0
    SET @SQL = @SQL+ 'c.Date_redeemed BETWEEN @start AND @end'    

    EXECUTE dbo.sample @type='Earn',@start='2010-02-10',@end='2020-04-11'
END
sql-server stored-procedures where-clause dynamic-sql
1个回答
0
投票

浏览过此内容后,我实际上不太愿意发布此答案,因为此错误太多了:

  • 易于SQL注入;
  • 使用过时的JOIN语法;
  • 笨拙的逻辑。

简单的答案是,有时仅仅因为您可以在SQL中执行某些操作并不意味着您实际上应该这样做。

无论如何,我认为更接近您想要的?

CREATE PROCEDURE dbo.[sample] (
    @start DATE, 
    @end DATE, 
    @type VARCHAR(5),
    @price1 NUMERIC(9,2),
    @price2 NUMERIC(9,2))
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @sql VARCHAR(1024);
    SELECT @sql = N'
        SELECT DISTINCT 
            o.O_Id,
            o.Sale_Price,
            o.Order_Line_Id,
            Private_Band, --alias?
            c.Date_of_Purchase,
            c.Date_Redeemed,
            c.Credit_Memo,
            c.Credit_Memo_Created_Date,
            c.Credit_Memo_Approved_Date,
            c.Type,
            c.Points_Issued,
            o.Date_of_Purchase 
        FROM 
            Order_Details o, 
            Transaction_Historys c'; --Join condition?!
    DECLARE @constraint VARCHAR(1024) = '';
    IF @type IS NOT NULL AND @type != 0            
    BEGIN
        SELECT @constraint = CONCAT(' WHERE c.Type = ''', @type, '''');
    END;
    IF @start IS NOT NULL AND @end IS NOT NULL
    BEGIN
        SELECT @constraint = CONCAT(@constraint, 
            CASE WHEN @constraint = '' THEN ' WHERE ' ELSE ' AND ' END, 
            ' c.Date_redeemed BETWEEN ''', 
            CONVERT(VARCHAR(12), @start, 112), 
            ''' AND ''', 
            CONVERT(VARCHAR(12), @end, 112)),
            '''';    
    END;
    SELECT @sql = CONCAT(@sql, @constraint);
    EXEC sp_executesql @sql;
END;
GO
EXEC dbo.[sample] @type = 'Earn', @start = '20100210', @end = '20200411', @price1 = NULL, @price2 = NULL;

我在这里做了很多更改:

  • 我无法让自己使用MONEY类型,因此,如果您确实需要,请改回来;
  • 我在您的脚本中添加了一些评论;)
  • 我已经解决了实际问题,您需要应对一两个或什至没有任何约束。
© www.soinside.com 2019 - 2024. All rights reserved.