zoukankan      html  css  js  c++  java
  • 如何在存储过程的IN操作中传递字符串变量

    原始SQL如下:

    SELECT   MONTH(OrderTime) AS datetype, SUM(DeliveryCount) AS decount, Region
    FROM      (SELECT   dbo.mpc_Order.OrderTime, 
                                     dbo.mpc_Order.Province + '-' + dbo.mpc_Order.City + '-' + dbo.mpc_Order.Area AS Region, 
                                     dbo.mpc_Order_Delivery.DeliveryCount
                     FROM      dbo.mpc_Order INNER JOIN
                                     dbo.mpc_Order_Delivery ON dbo.mpc_Order.OrderID = dbo.mpc_Order_Delivery.OrderID) AS T1
                                      WHERE Region IN('天津市-市辖区-和平区','吉林省-长春市-市辖区')
    GROUP BY Region, MONTH(OrderTime)

    因为项目需要,我需要把IN里的字符串做为一个参数,并写成存储过程进行调用,IN里面明显是一个字符串,所以很自然的写出如下存储过程:

    ALTER PROCEDURE [dbo].[QueryAgentOrder] 
        -- Add the parameters for the stored procedure here
        @Region NVARCHAR(1000),
        @QueryBy NVARCHAR(10)
    AS
    BEGIN
        DECLARE @SQL NVARCHAR(1000);    --SQL
        DECLARE @PARAM NVARCHAR(1000);    --参数
        IF @QueryBy = 'MONTh' OR @QueryBy = 'YEAR'
        BEGIN
            --SET @Region = '''天津市-市辖区-和平区'',''山东省-滨州市-邹平县''';
            SET @SQL = N'SELECT ' + @QueryBy + '(OrderTime) AS datetype, SUM(DeliveryCount) AS decount, Region';
            SET @SQL = @SQL + ' FROM      (SELECT   dbo.mpc_Order.OrderTime, ';
            SET @SQL = @SQL + ' dbo.mpc_Order.Province + ''-'' + dbo.mpc_Order.City + ''-'' + dbo.mpc_Order.Area AS Region,';
            SET @SQL = @SQL + ' dbo.mpc_Order_Delivery.DeliveryCount';
            SET @SQL = @SQL + ' FROM      dbo.mpc_Order INNER JOIN';
            SET @SQL = @SQL + ' dbo.mpc_Order_Delivery ON dbo.mpc_Order.OrderID = dbo.mpc_Order_Delivery.OrderID';        
            SET @SQL = @SQL + ' ) AS T1';
            IF @Region IS NOT NULL
                BEGIN
                    --这里传递@Region参数
                    SET @SQL = @SQL + ' WHERE Region IN(@Region)';
                END
            SET @SQL = @SQL + ' GROUP BY Region, ' + @QueryBy + '(OrderTime)';
    
            --申明参数
            SET @PARAM = N'@Region NVARCHAR(1000),@QueryBy NVARCHAR(10)';
    
            --执行存储过程
            EXEC sys.sp_executesql @SQL,@PARAM,@Region = @Region,@QueryBy = @QueryBy
        END
    END

    用以下方式调用,没有得到的记录:

    EXEC    [dbo].[QueryAgentOrder]
            @Region = N'天津市-市辖区-和平区,吉林省-长春市-市辖区',
            @QueryBy = N'month'

    换一种方式调用,还是不行:

    EXEC    [dbo].[QueryAgentOrder]
            @Region = N'''天津市-市辖区-和平区'',''吉林省-长春市-市辖区''',
            @QueryBy = N'month'

    其实关键还是出在如何传递Region变量上。后来看到两篇帖子,经过测试,得到两种正确的方法如下:

    第一种方法:

    在Region两边用单引号和加号+再连接一下,就可以。至于为什么,不清楚。。。

    ALTER PROCEDURE [dbo].[QueryAgentOrder] 
        -- Add the parameters for the stored procedure here
        @Region NVARCHAR(1000),
        @QueryBy NVARCHAR(10)
    AS
    BEGIN
        DECLARE @SQL NVARCHAR(1000);    --SQL
        DECLARE @PARAM NVARCHAR(1000);    --参数
        IF @QueryBy = 'MONTh' OR @QueryBy = 'YEAR'
        BEGIN
            SET @SQL = N'SELECT ' + @QueryBy + '(OrderTime) AS datetype, SUM(DeliveryCount) AS decount, Region';
            SET @SQL = @SQL + ' FROM      (SELECT   dbo.mpc_Order.OrderTime, ';
            SET @SQL = @SQL + ' dbo.mpc_Order.Province + ''-'' + dbo.mpc_Order.City + ''-'' + dbo.mpc_Order.Area AS Region,';
            SET @SQL = @SQL + ' dbo.mpc_Order_Delivery.DeliveryCount';
            SET @SQL = @SQL + ' FROM      dbo.mpc_Order INNER JOIN';
            SET @SQL = @SQL + ' dbo.mpc_Order_Delivery ON dbo.mpc_Order.OrderID = dbo.mpc_Order_Delivery.OrderID';        
            SET @SQL = @SQL + ' ) AS T1';
            IF @Region IS NOT NULL
                BEGIN
                    --在@Region两边加单引号
                    SET @SQL = @SQL + ' WHERE Region IN('+ @Region + ')';
                END
            SET @SQL = @SQL + ' GROUP BY Region, ' + @QueryBy + '(OrderTime)';
    
            --申明参数
            SET @PARAM = N'@Region NVARCHAR(1000),@QueryBy NVARCHAR(10)';
    
            --执行存储过程
            EXEC sys.sp_executesql @SQL,@PARAM,@Region = @Region,@QueryBy = @QueryBy
        END
    END

    调用方法:

    EXEC    [dbo].[QueryAgentOrder]
            @Region = N'''天津市-市辖区-和平区'',''吉林省-长春市-市辖区''',
            @QueryBy = N'month'

    调用结果:

    第二种方法:

     使用一个自定义函数,模拟split实现,然后通过select调用函数,感觉这种方法比较好。

    ALTER PROCEDURE [dbo].[QueryAgentOrder] 
        -- Add the parameters for the stored procedure here
        @Region NVARCHAR(1000),
        @QueryBy NVARCHAR(10)
    AS
    BEGIN
        DECLARE @SQL NVARCHAR(1000);    --SQL
        DECLARE @PARAM NVARCHAR(1000);    --参数
        IF @QueryBy = 'MONTh' OR @QueryBy = 'YEAR'
        BEGIN
            SET @SQL = N'SELECT ' + @QueryBy + '(OrderTime) AS datetype, SUM(DeliveryCount) AS decount, Region';
            SET @SQL = @SQL + ' FROM      (SELECT   dbo.mpc_Order.OrderTime, ';
            SET @SQL = @SQL + ' dbo.mpc_Order.Province + ''-'' + dbo.mpc_Order.City + ''-'' + dbo.mpc_Order.Area AS Region,';
            SET @SQL = @SQL + ' dbo.mpc_Order_Delivery.DeliveryCount';
            SET @SQL = @SQL + ' FROM      dbo.mpc_Order INNER JOIN';
            SET @SQL = @SQL + ' dbo.mpc_Order_Delivery ON dbo.mpc_Order.OrderID = dbo.mpc_Order_Delivery.OrderID';        
            SET @SQL = @SQL + ' ) AS T1';
            IF @Region IS NOT NULL
                BEGIN
                    --通过SPLIT函数分割生成结果集
                    SET @SQL = @SQL + ' WHERE Region IN(SELECT * FROM DBO.F_SPLIT(@Region,'',''))';                
                END
            SET @SQL = @SQL + ' GROUP BY Region, ' + @QueryBy + '(OrderTime)';
    
            --申明参数
            SET @PARAM = N'@Region NVARCHAR(1000),@QueryBy NVARCHAR(10)';
    
            --执行存储过程
            EXEC sys.sp_executesql @SQL,@PARAM,@Region = @Region,@QueryBy = @QueryBy
        END
    END

    调用方式也比较简单,相比第一种不用输入那么多的单引号:

    EXEC    [dbo].[QueryAgentOrder]
            @Region = N'天津市-市辖区-和平区,吉林省-长春市-市辖区',
            @QueryBy = N'month'

    调用结果:

    附:分割函数如下:

    create function f_split(@SourceSql varchar(8000),@StrSeprate varchar(10))
    returns @temp table(a varchar(100))
    --实现split功能 的函数
    --date    :2003-10-14
    as 
    begin
        declare @i int
        set @SourceSql=rtrim(ltrim(@SourceSql))   --去掉字符中的空格
        set @i=charindex(@StrSeprate,@SourceSql)  --找分割符在字符中的位置
        while @i>=1
        begin
            insert @temp values(left(@SourceSql,@i-1))  
            set @SourceSql=substring(@SourceSql,@i+1,len(@SourceSql)-@i)
            set @i=charindex(@StrSeprate,@SourceSql)
        end
        if @SourceSql<>'' 
           insert @temp values(@SourceSql)
        return 
    end

    最后


    上述两种方法都可以实现在IN中传递字符串变量,对于防注方面,感觉第二种应该比第一种好,有精于此块的朋友,也请不吝赐教。

  • 相关阅读:
    ranorex
    vue.js
    逻辑思维
    laravel-luntan
    python学习--基础
    git
    Laravel-高级篇-Auth-数据迁移-数据填充
    Laravel-高级篇-Artisan
    Laravel-表单篇-零散信息
    Laravel-表单篇-controller
  • 原文地址:https://www.cnblogs.com/superfeeling/p/9650717.html
Copyright © 2011-2022 走看看