【问题标题】:Dynamic T-SQL stored procedure to insert in differents tables插入不同表的动态 T-SQL 存储过程
【发布时间】:2015-10-03 13:17:56
【问题描述】:

实现这一目标的最佳方法是什么

INSERT INTO @TableName (@ColumnNames)
    EXEC sp_executesql @SQLResult;

其中@TableName@ColumnNames@SQLResultvarchar 变量

我试图避免为每个表单独插入。

【问题讨论】:

  • 不要。使用案例陈述或调查为什么您的 api 是这样设计的。
  • @Hogan 我试图避免一个案例,因为我现在需要填充 23 个不同的表。 TableName 是我用来插入表的 SP 的参数
  • 听起来设计很糟糕。老实说,如果可行的话,我会尝试重新设计任何流程。
  • 只写23个存储过程。如果这很难,您可以使用更安全、运行更快且设计更好的动态 HTML 来制作程序。
  • @SantiagoSalaberry 考虑到缺点,您不想避免编写 23 个插入过程。另请在 DBA.StackExchange 上查看这个几乎相同的问题:dba.stackexchange.com/questions/105541/…

标签: sql-server tsql stored-procedures dynamic


【解决方案1】:

最好的方法是为所有表编写(或生成)所有必需的过程。与所谓的“通用解决方案”相比,可以自动生成的 23 个表乘以 4 个过程(插入、更新、删除和选择)在开发时间和痛苦中算不了什么。

这是一条导致性能不佳、代码不可读、sql 注入危险和无数调试时间的途径。

【解决方案2】:

首先,我感谢您的所有 cmets。而且我同意 SQL 动态调试很痛苦(感谢上帝,管理工作室有这种可能性)。而且,当然有数百种不同的解决方案

我终于这样解决了,我或多或少地试图解释为什么这个SQL动态的解决方案。客户端使用 xlsx 电子表格输入某些数据,所以我读取电子表格并插入(数据取决于电子表格插入到正确的表中)。稍后将表中的数据导出为 XML 以发送给第三方软件。

SET @SEL = N'';
DECLARE sel_cursor CURSOR
FOR (SELECT  sc.name as field
      FROM sys.objects so INNER JOIN sys.columns sc ON so.[object_id]=sc.[object_id]
      WHERE so.name= @TableName and sc.name not in ('InitDate', 'EndDate', 'Version', 'Status'));

SET @SEL = ''; set @i = 0;
OPEN sel_cursor
FETCH NEXT FROM sel_cursor INTO @field
WHILE @@FETCH_STATUS = 0
BEGIN
    set @sel = @sel + ', '+ @field 
    set @i   = 1;
    FETCH NEXT FROM sel_cursor INTO @field
END
CLOSE sel_cursor;
DEALLOCATE sel_cursor;


SET @SQL = N''
SET @SQL = @SQL + N'SELECT * INTO XLImport FROM OPENROWSET'
SET @SQL = @SQL + N'('
SET @SQL = @SQL + N'''Microsoft.ACE.OLEDB.12.0'''+','
SET @SQL = @SQL + N'''Excel 12.0 Xml; HDR=YES;'
SET @SQL = @SQL + N'Database='+@file +''''+ ','
SET @SQL = @SQL + N'''select * from ['+ @SheetName + '$]'''+');'

EXEC sp_executesql @SQL

SET @SQL = N'';
SET @SQL = @SQL + N'
SELECT '+''''+CAST(@initDate AS VARCHAR(10))+'''' +', '+ ''''+CAST(@endDate AS VARCHAR(10))+'''' 
      + ', '+ CAST(@version AS VARCHAR(2)) +', ' +''''+@status+''''
      + @SEL 
 +'    FROM DBO.XLImport '


DECLARE cols_cursor CURSOR
   FOR (Select COLUMN_NAME From INFORMATION_SCHEMA.COLUMNS where table_name = @tableName);
SET @SEL = ''; set @i = 0;
OPEN cols_cursor
FETCH NEXT FROM cols_cursor INTO @field
WHILE @@FETCH_STATUS = 0
BEGIN
   set @sel = @sel + @field + ', '
   set @i   = 1;
   FETCH NEXT FROM cols_cursor INTO @field
END
CLOSE cols_cursor;
DEALLOCATE cols_cursor;

SET @SEL = LEFT(@SEL, LEN(@SEL) - 1) -- remove last ,


SET @SQL = N''
SET @SQL = @SQL + N'SELECT * INTO XLImport FROM OPENROWSET'
SET @SQL = @SQL + N'('
SET @SQL = @SQL + N'''Microsoft.ACE.OLEDB.12.0'''+','
SET @SQL = @SQL + N'''Excel 12.0 Xml; HDR=YES;'
SET @SQL = @SQL + N'Database='+@file +''''+ ','
SET @SQL = @SQL + N'''select * from ['+ @SheetName + '$]'''+');'

EXEC sp_executesql @SQL

SET @SQLString =
N'INSERT INTO '+ @TableName + '('+ @SEL +') ' + @SQL;

EXEC sp_executesql @SQLString

【讨论】:

    【解决方案3】:

    使用EXECUTE sp_executesql @sql,示例如下:

    create proc sp_DynamicExcuteStore 
    @TableName varchar(50),
    @ColumnNames varchar(50),
    @SQLResult varchar(max)
    as
    declare @sql nvarchar(max) = '
    INSERT INTO '+@TableName+' ('+@ColumnNames+')
        EXEC sp_executesql '+@SQLResult
    EXECUTE sp_executesql @sql
    go
    create proc sp_test
    as
    select 'test' + convert(varchar,RAND())
    go
    CREATE TABLE [dbo].[Test](
        [text1] [nvarchar](500) NULL
    ) ON [PRIMARY]
    
    GO
    DECLARE @return_value int
    
    EXEC    @return_value = [dbo].[sp_DynamicExcuteStore]
            @TableName = N'Test',
            @ColumnNames = N'text1',
            @SQLResult = N'proc_test'
    
    SELECT  'Return Value' = @return_value
    
    GO
    
    SELECT TOP 1000 [text1]
      FROM [test].[dbo].[Test]
    

    【讨论】:

      猜你喜欢
      • 2020-07-05
      • 2016-08-20
      • 1970-01-01
      • 2018-02-03
      • 1970-01-01
      • 2017-01-26
      • 1970-01-01
      • 2018-10-02
      • 2018-04-01
      相关资源
      最近更新 更多