【问题标题】:SQL Server : Dynamic functions or reuse of stored proceduresSQL Server:动态函数或存储过程的重用
【发布时间】:2015-04-28 15:06:52
【问题描述】:

我想使用一些动态的SELECT 语句。表或列的名称可能不同,这就是我使用这样的动态存储过程的原因:

CREATE PROCEDURE [dbo].[test_sp](
     @database nvarchar(70)= ''
    , @table_name nvarchar(70)= ''
    , @column nvarchar(70)= ''
) 
AS
    DECLARE @sql nvarchar(max)= 'SELECT ' + @column + 
                                'FROM [' + @database + 
                                '].[dbo].[' + @table_name + ']  ' 

    EXEC(@sql);
GO

这很好用。现在我得到了越来越多的具有类似代码 sn-ps 的存储过程。关于维护,我想重用 sn-ps 或使用动态功能。

一个例子:我有另一个存储过程应该“过滤”这个例子的结果集(一个额外的要求是不要添加一个参数来直接过滤这个结果集)

如果这个 SQL 是静态的,我会使用一个函数。在我的情况下,我需要那种动态。 UDF 不允许“EXEC”-stuff 和存储过程的结果集不可重用。

我希望很多人都像我一样遇到这个问题。我用谷歌搜索了很多东西并尝试了几件事,但没有任何效果......

我需要一种方法来重用存储过程代码 sn-ps 或重用存储过程的结果集或像存储过程一样动态的函数。

那么谁能帮助我并给我另一个想法?

感谢您的帮助或解决方案的想法:)

V

编辑/解决方案:
首先每个人都应该阅读“Joel Coehoorn”和“Panagiotis Kanavos”的评论。他们是绝对正确的,并且不建议在 Web 应用程序或类似的东西中使用此代码 sn-ps。在我的特殊情况下,它是一个本地应用程序,注入和其他安全方面不相关。

在那之后,我要感谢“Abdul Rehman Sayed”。以下解决方案基于他的想法。

要在 SQL 中实现这一要求,您必须创建两个存储过程。首先是创建一个结果集并将其写入临时表。

第二个执行第一个存储过程,过滤结果并删除临时表。

第一个:

ALTER PROCEDURE [dbo].[test_SP_FXN](
 @database nvarchar(70)= ''
) AS

DECLARE @create nvarchar(max)= '
    CREATE TABLE ['+@database+'].[dbo].[temp_result](
    [name] [nvarchar](150) NULL
  ,[id] [nvarchar](150) NULL
  ,[desc] [nvarchar](450) NULL )  ';

DECLARE @sql nvarchar(max)= '
INSERT INTO ['+@database+'].[dbo].[temp_result]
    SELECT TOP 1000 name, id, desc
    FROM ['+@database+'].[dbo].[important_table] ';

EXEC(@create);
EXEC(@sql);

第二个:

ALTER PROCEDURE [dbo].[test_SP_2](
 @database nvarchar(70)= ''
) AS
-- create the temp table with the result of the store procedure
EXEC ('['+@database+'].[dbo].[test_SP_FXN] '+@database )

-- Execute the real sql
DECLARE @sql nvarchar(max)= 'select * FROM ['+@database+'].[dbo].[temp_result] WHERE ID > 5' 
EXEC(@sql);

-- drop the temp table because there is no use any more
EXEC ('DROP TABLE ['+@database+'].[dbo].[temp_result] ')

这只是一个例子,但我认为原理会很清楚。

感谢您的帮助和 cmets。

【问题讨论】:

  • 这看起来像是 sql 注入攻击的噩梦。
  • 你需要这个过程的结果在一个临时表中吗??
  • SQL(语言)不是这样工作的。您不会在多个表上“重用”语句。表相当于一种类型,您不能拥有适用于任意类型的方法。这个存储过程不是“动态的”,它只是一个使用连接创建的字符串。事实上,客户端生成的 SQL 语句(例如来自 ORM)会执行得更好并且更安全。事实上,它打开了安全漏洞(需要访问不同的数据库),打开数据库以进行注入攻击,否定执行计划缓存的任何好处,并且可以升级为分布式事务
  • 这是一个本地应用程序。这就是为什么安全方面不那么重要的原因。但是您在普通的 Web 应用程序中是对的,这太糟糕了! @Abdul我可能使用临时表来获取存储过程的结果集。我会尝试一个可能的解决方案,谢谢你的提示。

标签: sql-server stored-procedures


【解决方案1】:

通过另一种方式,您可以将存储过程更改为以下内容:

CREATE PROCEDURE [dbo].[test_sp](
    , @Select nvarchar(70)= ''
    , @From nvarchar(70)= ''
    , @Where nvarchar(max) = ''
    , @GroupByColumn nvarchar(max) = ''
    , @Having nvarchar(max) = ''
    , @OrderBy nvarchar(max) = ''
) 
AS
    DECLARE @sql nvarchar(max)= 'SELECT ' + @Select + 
                                'FROM ' + @From + 
                                CASE WHEN @Where = '' THEN '' ELSE ' WHERE ' + @Where END +
                                CASE WHEN @GroupByColumn = '' THEN '' ELSE ' GROUP BY ' + @GroupByColumn END +
                                CASE WHEN @Having = '' THEN '' ELSE ' HAVING ' + @Having END +
                                CASE WHEN @OrderBy = '' THEN '' ELSE ' ORDER BY ' + @OrderBy END

    EXEC(@sql);
GO

现在你可以像这样测试它:

EXEC test_sp @Select = 'Column1, Column2', @From = 'Table1'

EXEC test_sp @Select = 'DISTINCT Table1.Column1, Table2.Column1', @FROM = 'Table1 INNER JOIN TABLE2 ON Table1.PK = Table2.FK'

EXEC test_sp  @Select = 't1.[datetime]', @From = '[TestDB].[dbo].[Table1] t1', @Where = 't1.NullableColumn IS NOT NULL'

EXEC test_sp @Select = 'Column1, Column2', @From = 'Table1', @OrderBy = 'Column2'

等等……

【讨论】:

    【解决方案2】:

    我想你正在寻找这样的东西:

    Declare @table Table(/* list of columns */)
    
    insert into @table
    EXEC test_sp 'aDbName','aTable','somecolumns'
    
    select *
    from @table
    where /* some filters */
    

    【讨论】:

    • @Der_V 你可以使用 Table 变量而不是在你的第一个表中创建一个表,你不需要删除它;)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-27
    • 2016-01-07
    • 2020-01-15
    • 2015-04-24
    • 1970-01-01
    • 1970-01-01
    • 2010-09-13
    相关资源
    最近更新 更多