Sql server SQL Server:动态函数或存储过程的重用

Sql server SQL Server:动态函数或存储过程的重用,sql-server,stored-procedures,Sql Server,Stored Procedures,我想使用一些动态SELECT语句。表或列的名称可能不同,这就是为什么我使用如下动态存储过程: CREATE PROCEDURE [dbo].[test_sp]( @database nvarchar(70)= '' , @table_name nvarchar(70)= '' , @column nvarchar(70)= '' ) AS DECLARE @sql nvarchar(max)= 'SELECT ' + @column +

我想使用一些动态
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
Declare @table Table(/* list of columns */)

insert into @table
EXEC test_sp 'aDbName','aTable','somecolumns'

select *
from @table
where /* some filters */
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'
这很有效。现在,我得到了越来越多的具有类似代码片段的存储过程。关于维护,我希望重用代码片段或使用动态函数

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

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

我想很多人也会像我一样遇到这个问题。我在谷歌上搜索了很多,尝试了很多东西,但都没用

我需要一种方法来重用存储过程代码片段,或者重用存储过程或像存储过程一样动态的函数的结果集

有谁能帮我再给我一个主意吗

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

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

“在那之后,我必须感谢你,”阿卜杜勒·雷赫曼说。下面的解决方案基于他的想法

要在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] ')
这只是一个例子,但我认为原则是明确的


感谢您的帮助和评论。

我想您正在搜索以下内容:

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
Declare @table Table(/* list of columns */)

insert into @table
EXEC test_sp 'aDbName','aTable','somecolumns'

select *
from @table
where /* some filters */
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'

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

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
Declare @table Table(/* list of columns */)

insert into @table
EXEC test_sp 'aDbName','aTable','somecolumns'

select *
from @table
where /* some filters */
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'
现在您可以这样测试它:

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
Declare @table Table(/* list of columns */)

insert into @table
EXEC test_sp 'aDbName','aTable','somecolumns'

select *
from @table
where /* some filters */
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'

以此类推……

这看起来像是sql注入攻击的噩梦。您需要临时表中此过程的结果吗?sql(语言)不是这样工作的。不能“重用”多个表上的语句。一个表相当于一个类型,不能有处理任意类型的方法。此存储过程不是“动态”的,它只是使用串联创建的字符串。事实上,客户机生成的SQL语句(例如从ORM生成的SQL语句)将执行得更好、更安全。事实上,它打开了安全漏洞(需要访问不同的数据库),使数据库面临注入攻击,否定了执行计划缓存的任何好处,并可能升级为分布式事务。它是一个本地应用程序。这就是为什么安全方面没有那么重要。但是在一个普通的web应用程序中你是对的,这太可怕了@Abdul我可能使用临时表来获取存储过程的结果集。我将尝试一个可能的解决方案,谢谢您的提示。@deru\V您可以使用Table变量,而不是在第一个变量中创建一个表,并且您不需要删除它;)。