【问题标题】:SQL Server : Insert Values into a Table with one Dynamic Query, constants, etcSQL Server:使用一个动态查询、常量等将值插入表中
【发布时间】:2018-03-29 23:22:01
【问题描述】:

我有以下查询,将一些值插入到一个表中,这是有效的:

INSERT INTO Table(id, field_1, field_2, field_3, field_4)
 SELECT (SELECT INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME + FORMAT(convert (datetime,date)  ,   'ddMMyyyy') +@MAINFIELD+@FIELDTYPE), @MAINFIELD, date , @ColumnName, '0'
FROM kat.[dbo].[Imported_Table]
INNER JOIN INFORMATION_SCHEMA.COLUMNS   on INFORMATION_SCHEMA.COLUMNS.TABLE_NAME =  @TABLENAME and INFORMATION_SCHEMA.COLUMNS.ORDINAL_POSITION = @CurrentPosition

这工作正常。当我想在表中插入一个新值并且这个值是从动态查询中获得时,问题就来了:

这是单独工作的查询(变量已定义)

EXEC ('SELECT '+@ColumnName+' from kat.[dbo].[Imported_Table]')

如果我想将它包含在插入查询中,但我认为这是不可能的。至少它不是为我编译的:

INSERT INTO Table(id, field_1, field_2, field_3, field_4, **field_5**)
 SELECT (SELECT INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME + FORMAT(convert (datetime,date)  ,   'ddMMyyyy') +@MAINFIELD+@FIELDTYPE), @MAINFIELD, date , @ColumnName, '0', **EXEC ('SELECT '+@ColumnName+' from kat.[dbo].[Imported_Table]')**
FROM kat.[dbo].[Imported_Table]
INNER JOIN INFORMATION_SCHEMA.COLUMNS   on INFORMATION_SCHEMA.COLUMNS.TABLE_NAME =  @TABLENAME and INFORMATION_SCHEMA.COLUMNS.ORDINAL_POSITION = @CurrentPosition

也许有更好的解决方案将此动态查询包含在插入子句中?

编辑:在 Nisarg cmets 和支持后,我调整了查询​​:

set @MAINFIELD=  CAST(@MAINCURRENCY AS VARCHAR);
set @FIELDTYPE=  CAST(@RATETYPE AS VARCHAR);
SET @ColumnName = CAST(@ColumnName AS VARCHAR)
SET @CurrentPosition = CAST(@CurrentPosition AS INT)
EXEC( 'INSERT INTO Devisen_geldkurs(devisen_geldkurs, field_1, field_2, field_3, field_4, field_5) 
SELECT (SELECT INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME + FORMAT(convert (datetime,date)  ,   ''ddMMyyyy'') +''@MAINFIELD''+''@FIELDTYPE''), "@MAINFIELD", date , "@ColumnName", ''0'', 
    SELECT '+@ColumnName+' from kat.[dbo].[Imported_Table] from kat.[dbo].[Imported_Table]
    INNER JOIN INFORMATION_SCHEMA.COLUMNS   on INFORMATION_SCHEMA.COLUMNS.TABLE_NAME =  "Imported_Table" and INFORMATION_SCHEMA.COLUMNS.ORDINAL_POSITION = ''@CurrentPosition''')

似乎唯一的问题在于 SELECT 子句:

Incorrect syntax near the keyword 'SELECT'.

我还删除了以下内容之一:from kat.[dbo].[Imported_Table] FROM kat.[dbo].[Imported_Table]。写了两次。

【问题讨论】:

    标签: sql sql-server schema sql-insert dynamic-sql


    【解决方案1】:

    您不能只在查询中间编写动态查询。但是您可以将整个查询转换为动态查询:

    EXEC( 'INSERT INTO Table(id, field_1, field_2, field_3, field_4, field_5) 
    SELECT (SELECT INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME + FORMAT(convert (datetime,date)  ,   ''ddMMyyyy'') +@MAINFIELD+@FIELDTYPE), @MAINFIELD, date , @ColumnName, ''0'', 
        SELECT '+@ColumnName+' from kat.[dbo].[Imported_Table] FROM kat.[dbo].[Imported_Table] 
        INNER JOIN INFORMATION_SCHEMA.COLUMNS   on INFORMATION_SCHEMA.COLUMNS.TABLE_NAME =  @TABLENAME and INFORMATION_SCHEMA.COLUMNS.ORDINAL_POSITION = @CurrentPosition')
    

    请先通过PRINTing 进行检查,以确保查询没有任何语法错误。

    另外,您应该避免使用EXEC。相反,您可以使用sp_executesql,它可以更好地防止动态查询的 SQL 注入。

    更新

    我之前错过了将 SELECT 子查询括在括号中。应该是这样的。请注意下面第 7 行中的 (SELECT TOP 1 '+@ColumnName+' from kat.[dbo].[Imported_Table]) as field_5 语句:

    set @MAINFIELD=  CAST(@MAINCURRENCY AS VARCHAR);
    set @FIELDTYPE=  CAST(@RATETYPE AS VARCHAR);
    SET @ColumnName = CAST(@ColumnName AS VARCHAR)
    SET @CurrentPosition = CAST(@CurrentPosition AS INT)
    EXEC( 'INSERT INTO Devisen_geldkurs(devisen_geldkurs, field_1, field_2, field_3, field_4, field_5) 
    SELECT (SELECT INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME + FORMAT(convert (datetime,date)  ,   ''ddMMyyyy'') +''@MAINFIELD''+''@FIELDTYPE''), "@MAINFIELD", date , "@ColumnName", ''0'', 
        (SELECT TOP 1 '+@ColumnName+' from kat.[dbo].[Imported_Table]) as field_5
        from kat.[dbo].[Imported_Table]
        INNER JOIN INFORMATION_SCHEMA.COLUMNS   on INFORMATION_SCHEMA.COLUMNS.TABLE_NAME =  "Imported_Table" and INFORMATION_SCHEMA.COLUMNS.ORDINAL_POSITION = ''@CurrentPosition''')
    

    或者,由于您使用的是动态查询,因此以下内容也应该可以工作。我删除了子查询,并在查询中附加了字段名称。

    set @MAINFIELD=  CAST(@MAINCURRENCY AS VARCHAR);
    set @FIELDTYPE=  CAST(@RATETYPE AS VARCHAR);
    SET @ColumnName = CAST(@ColumnName AS VARCHAR)
    SET @CurrentPosition = CAST(@CurrentPosition AS INT)
    EXEC( 'INSERT INTO Devisen_geldkurs(devisen_geldkurs, field_1, field_2, field_3, field_4, field_5) 
    SELECT (SELECT INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME + FORMAT(convert (datetime,date)  ,   ''ddMMyyyy'') +''@MAINFIELD''+''@FIELDTYPE''), "@MAINFIELD", date , "@ColumnName", ''0'', '+@ColumnName+'
    
    from kat.[dbo].[Imported_Table]
    INNER JOIN INFORMATION_SCHEMA.COLUMNS   on INFORMATION_SCHEMA.COLUMNS.TABLE_NAME =  "Imported_Table" and INFORMATION_SCHEMA.COLUMNS.ORDINAL_POSITION = ''@CurrentPosition''')
    

    【讨论】:

    • 嗨,非常感谢查询转换和有关 sp_executesql 的提示。但是,当尝试运行新查询(也只是尝试在插入之前选择)时,不再检测到所有定义的变量:@MAINFIELD, FIELDTYPE...
    • 嗯,我之前没有注意到它们。有两种方法:(1)将它们作为 varchar 附加到查询并使用 EXEC 执行查询,或者(2)将它们作为参数传递给 sp_executesql
    • 您好,关于第一个选项,您的意思是在执行查询之前将变量转换为 Varchar?也许是这样的?设置@MAINFIELD='+@MAINFIELD+'
    • @Katherine99 是的,应该可以。只需确保在附加到查询之前将变量转换为适当大小的varchar。此外,如果它们应该是字符串,则需要在查询中的变量周围插入单引号。因此,正如我所提到的,最好在运行查询之前PRINT 以避免语法问题。
    • 您好 Nisarg,由于查询的复杂性,我最终决定选择 sp_executesql。我基于此转换了查询,它似乎有效。目前查询运行但没有插入任何内容,因为由于 ' ' 分隔符,它没有检测到表名。我希望找到解决方案,这会奏效。
    【解决方案2】:

    您可以使用 INSERT EXEC。您必须在动态查询内部和外部声明表的变量。 在动态查询结束时,只需从表变量中选择并将结果集插入到外部表变量中

    DECLARE @table SomeTable ( ID INT ) 
    
    DECLARE @query NVARCHAR(120) = 'declare @table  SomeTable (id int) 
                                    insert into @table  values(1),(2) 
                                    select * from @table '
    
    INSERT INTO @table 
    EXEC(@query)
    
    SELECT * FROM @table 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多