在存储过程命令中构建动态where子句

时间:2019-01-11 19:16:32

标签: c# sql-server ssms-2016

我有一个存储过程,其中的参数看起来像这样

Create Procedure [dbo].[myStoredProcedure]
    @TaskId int = 0
,   @FileName varchar(200) =''
,   @DataDtFrom     smalldatetime = '01/01/1900'
,   @DataDtTo       smalldatetime = '01/01/1900'
,   @OFFSET INT = 0
,   @FETCH INT = 2000
,   @WhereClauseString varchar(5000) = ''

SELECT 
         DataDt
        ,EffDt
        ,LoanNumber     
        ,UploadDate
        ,UploadedFileName       
  FROM dbo.myFileTable u
    WHERE  
        (@DataDtTo = '01/01/1900' or DataDt between @DataDtFrom and @DataDtTo)      
        and (@TaskId = 0 or TaskId = @TaskId)
        and (@FileName = '' or UploadedFileName like '%' + @FileName + '%')

        **Where ??? = @WhereClauseString**

        ORDER BY u.UploadDate
        OFFSET @OFFSET ROWS 
        FETCH NEXT @FETCH ROWS ONLY

我用C#初始化

 var whereClauseString = "LoanNum in(111,222,444) and TaskId in (123,456,789)";

 using (var conn = new MyEntities().Database.Connection)
                    {
                        conn.Open();
                        var cmd = conn.CreateCommand();
                        cmd.CommandTimeout = 1800;
                        cmd.CommandText = model.UploadStoredProcedure;
                        cmd.CommandType = System.Data.CommandType.StoredProcedure;
                        cmd.Parameters.Add(new System.Data.SqlClient.SqlParameter("@TaskId", Convert.ToInt64(model.TaskId)));
                        cmd.Parameters.Add(new System.Data.SqlClient.SqlParameter("@FileName", model.FileName ?? string.Empty));

                        cmd.Parameters.Add(new System.Data.SqlClient.SqlParameter("@DataDtFrom", DateTime.Parse(model.adjFromDataDt.ToShortDateString()) <= DateTime.Parse(basicDate.ToShortDateString()) ? basicDate : model.adjFromDataDt.Date));
                        cmd.Parameters.Add(new System.Data.SqlClient.SqlParameter("@DataDtTo", DateTime.Parse(model.adjToDataDt.ToShortDateString()) <= DateTime.Parse(basicDate.ToShortDateString()) ? basicDate : model.adjToDataDt.Date));                       
                        cmd.Parameters.Add(new System.Data.SqlClient.SqlParameter("@OFFSET", model.Page));
                        cmd.Parameters.Add(new System.Data.SqlClient.SqlParameter("@FETCH", model.PageSize));  

    **Dynamic Where clause** -->> System.Data.SqlClient.SqlParameter("@WhereClause", whereClauseString));                      
                        var da = new System.Data.SqlClient.SqlDataAdapter((System.Data.SqlClient.SqlCommand)cmd);
                        da.Fill(ds);
                    }

我的问题是可以构建动态的where子句并将其传递给存储过程,然后对where子句中引用的列进行排序吗? 我如何知道在存储过程中需要在where子句中引用的列?

使用此存储过程和实体框架是否有可能?

1 个答案:

答案 0 :(得分:1)

无论如何,如果您的数据库远离SQL注入的外部攻击,您仍然可以考虑使用基于Dinamic SQL的简单解决方案,那么这种方法通常可以快速解决非常复杂的问题,否则:

CREATE Procedure [dbo].[myStoredProcedure]
    @TaskId int = 0
,   @FileName varchar(200) =''
,   @DataDtFrom     smalldatetime = '01/01/1900'
,   @DataDtTo       smalldatetime = '01/01/1900'
,   @OFFSET INT = 0
,   @FETCH INT = 2000
,   @WhereClauseString varchar(5000) = ''
AS
BEGIN
DECLARE @SQL AS NVARCHAR(MAX);
SELECT @SQL = '
SELECT 
         DataDt
        ,EffDt
        ,LoanNumber     
        ,UploadDate
        ,UploadedFileName       
  FROM dbo.myFileTable u
    WHERE  
        ('''+CONVERT(CHAR(10), @DataDtTo, 112)+''' = ''01/01/1900'' or DataDt between '''+CONVERT(CHAR(10), @DataDtFrom, 112)+''' and '''+CONVERT(CHAR(10), @DataDtTo, 112)+''')      
        and ('+CONVERT(CHAR(10), @TaskId)+' = 0 or TaskId = '+CONVERT(CHAR(10), @TaskId)+')
        and ('+RTRIM(CONVERT(CHAR(100), @FileName))+' = '''' or UploadedFileName like ''%'+RTRIM(CONVERT(CHAR(100), @FileName))+'%'')
        ' +CONVERT(CHAR(100), @WhereClauseString)+'
        ORDER BY u.UploadDate
        OFFSET '+CONVERT(CHAR(10), @OFFSET)+' ROWS 
        FETCH NEXT '+CONVERT(CHAR(10), @FETCH)+' ROWS ONLY;
        '
PRINT @SQL;
EXEC sp_ExecuteSQL @SQL;
END;