当前位置:网站首页>Dynamic query processing method of stored procedure

Dynamic query processing method of stored procedure

2020-11-08 19:03:00 Gently walk by

When querying stored procedure dynamic matching problems , See the parameter dynamic matching processing of the stored procedure , I found myself making mistakes in this respect , So rearrange it and save it .

Mode one :

The common way to write : Put together strings , use EXEC To execute this pieced up string , Not recommended

create proc pr_getOrederInfo_1
(
    @p_OrderNumber       int      ,
    @p_CustomerId        varchar(20) ,
    @p_OrderDateBegin    datetime   ,
    @p_OrderDateEnd      datetime
)
as
begin
    
    set nocount on;
    declare @strSql nvarchar(max);
    set @strSql= 'SELECT [id]
               ,[OrderNumber]
               ,[CustomerId]
               ,[OrderDate]
               ,[Remark]
            FROM [dbo].[SaleOrder] where 1=1 ';
    /*
         The characteristic of this method is to query SQL Put it together into a string , Finally EXEC The way to execute this SQL character string 
    */

    if(@p_OrderNumber is not null)
        set @strSql = @strSql + ' and OrderNumber = ' + @p_OrderNumber
    if(@p_CustomerId is not null)
        set @strSql = @strSql + ' and CustomerId  = '+ ''''+ @p_CustomerId + ''''
    if(@p_OrderDateBegin is not null)
        set @strSql = @strSql + ' and OrderDate >= ' + '''' + cast(@p_OrderDateBegin as varchar(10)) + ''''
    if(@p_OrderDateEnd is not null)
        set @strSql = @strSql + ' and OrderDate <= ' + '''' + cast(@p_OrderDateEnd as varchar(10)) + ''''

    print @strSql
    exec(@strSql);

end

There is no problem with the execution method itself , It turned out to be no problem . But there are disadvantages

1、 It can't bypass the transfer operator and the injection problem .

2、 Because the parameters are different , It's going to lead to every piece of sql Different , As a result, it needs to be compiled every time , waste CPU resources , There will be problems with large quantities .

Mode two :

  Use the OR The way to add to where In the condition , Very not recommended

create proc pr_getOrederInfo_2
(
    @p_OrderNumber      int      ,
    @p_CustomerId       varchar(20) ,
    @p_OrderDateBegin   datetime   ,
    @p_OrderDateEnd     datetime
)
as
begin
    
    set nocount on;

    declare @strSql nvarchar(max);

    SELECT [id]
            ,[OrderNumber]
            ,[CustomerId]
            ,[OrderDate]
            ,[Remark]
    FROM [dbo].[SaleOrder] 
    where 1=1
        and (@p_OrderNumber is null  or OrderNumber  = @p_OrderNumber)
        and (@p_CustomerId  is null  or CustomerId   = @p_CustomerId)
        /*
         This is another way of writing a similar exotic flower , The following will focus on 
        and  OrderNumber  = ISNULL( @p_OrderNumber,OrderNumber)
        and  CustomerId   = ISNULL( @p_CustomerId,CustomerId)
        */
        and (@p_OrderDateBegin is null or OrderDate  >= @p_OrderDateBegin)
        and (@p_OrderDateEnd is null   or OrderDate  <= @p_OrderDateEnd)
        
end

There is no problem with the execution method itself , It turned out to be no problem . But there are disadvantages

1、 Suppress index .

2、 So are the parameters null It's a terrible time .

Mode three :

A parameterized SQL, recommend

create proc pr_getOrederInfo_3
(
    @p_OrderNumber       int      ,
    @p_CustomerId        varchar(20) ,
    @p_OrderDateBegin    datetime   ,
    @p_OrderDateEnd      datetime
)
as
begin
    
       set nocount on;
    
      DECLARE @Parm         NVARCHAR(MAX) = N'',
              @sqlcommand   NVARCHAR(MAX) = N''

        SET @sqlcommand = 'SELECT [id]
                                  ,[OrderNumber]
                                  ,[CustomerId]
                                  ,[OrderDate]
                                  ,[Remark]
                            FROM [dbo].[SaleOrder] 
                            where 1=1 '
        
        IF(@p_OrderNumber IS NOT NULL)
            SET @sqlcommand = CONCAT(@sqlcommand,' AND OrderNumber= @p_OrderNumber')

        IF(@p_CustomerId IS NOT NULL)
            SET @sqlcommand = CONCAT(@sqlcommand,' AND CustomerId= @p_CustomerId')

        IF(@p_OrderDateBegin IS NOT NULL)
            SET @sqlcommand = CONCAT(@sqlcommand,' AND OrderDate>=@p_OrderDateBegin ')

        IF(@p_OrderDateEnd IS NOT NULL)
            SET @sqlcommand = CONCAT(@sqlcommand,' AND OrderDate<=@p_OrderDateEnd ')

        SET @Parm= '@p_OrderNumber        int,
                    @p_CustomerId        varchar(20),
                    @p_OrderDateBegin    datetime,
                    @p_OrderDateEnd        datetime '


        PRINT @sqlcommand
        EXEC sp_executesql @sqlcommand,@Parm,
                            @p_OrderNumber       =    @p_OrderNumber,
                            @p_CustomerId        =    @p_CustomerId,
                            @p_OrderDateBegin    =    @p_OrderDateBegin,
                            @p_OrderDateEnd      =    @p_OrderDateEnd 
        
end

There is no problem with the execution method itself , It turned out to be no problem .

First of all , It can avoid the first way of writing SQL Injection problem ( Including the handling of transfer characters ),
    Because the parameters are passed in at run time SQL Of , Instead of being passed in at compile time , The parameters passed are executed according to what they are , The parameter itself does not participate in compilation
second , Ensure reuse of execution plan , Because you use placeholders to piece together SQL Of ,SQL The value of the parameter is different and leads to the final execution of SQL Different texts
    Same as above , The parameter itself does not participate in compilation , If the query conditions are the same (SQL The sentence is the same ), And the parameters are different , It doesn't affect what you want to compile SQL Text information
Third , And the second situation is avoided (and (@p_CustomerId is null or CustomerId = @p_CustomerId)
    perhaps and OrderNumber = ISNULL( @p_OrderNumber,OrderNumber))
     This kind of writing , If the query condition is yes, there is , No is No , It won't be thrown to SQL Query engine results of one ambiguous two ,
     It avoids the inhibition of index , It is a better way to deal with query conditions .

 

After reading these , We found that we need to adjust some stored procedures that may be large in the future ...

inductive :

1、 Create a temporary table .

2、 Write the data to the temporary table in mode 3 .

3、 Traverse the temporary table and splice it into JSON String returns

The actual measurement added


declare
	@data1			NVARCHAR(20),
	@count			int,
	@sqlcommand   NVARCHAR(MAX) = N'',
	@Parm         NVARCHAR(MAX) = N''
begin 
	set @sqlcommand=' '
	set @data1=' 1 or 1=1'	
			
	set @sqlcommand=' select @a=COUNT(1) from tb_user  where 1=1 '	
	
	exec sp_executesql @sqlcommand,N'@a int output ',@count output
	
	print ' Number ='+convert(varchar(10),@count)
	
	set @sqlcommand=' '
	set @sqlcommand=N' select id,u_no,u_name from tb_user  where 1=1 '	
	IF(@data1 IS NOT NULL) SET @sqlcommand += N' AND u_name like ''%'+@data1+'%'''
	
	print @sqlcommand
	exec sp_executesql @sqlcommand
end

result

That's it. First .............

All of a sudden, what I'm using now is .

create PROCEDURE pro_demo 
	@action    varchar(20)
AS	  
BEGIN	
	SET NOCOUNT ON;
--------------------------------------  Defining variables 
declare
	@method varchar(20),
	@err varchar(20)

	if @action='1'
	begin
		set @method='1'
		goto res
	end
	
	if @action='2'
	begin
		set @method='2'
		goto res
	end
	
	if @action='3'
	begin
		set @method='3'
		goto res
	end
	
	set @err=' Method does not match '
	--  It seems to be   Allied   Ah   To find a donkey by riding a donkey .......
	-- switch(){
	--	 case '1':
	--		 Method 1  ;
	--		break;
	--	 case '2':
	--		 Method 2  ;
	--		break;
	--	 case '3':
	--		 Method 3  ;
	--		break;
	--	 default:
	--		 error   ;
	--		break;
	-- }
	res:
END
GO

 

版权声明
本文为[Gently walk by]所创,转载请带上原文链接,感谢