代码之家  ›  专栏  ›  技术社区  ›  WJTownsend

在动态SQL SELECT语句中提供字符串变量,而不将其作为列名读取?

  •  0
  • WJTownsend  · 技术社区  · 6 月前

    我遇到了这样一种情况,即我正试图在Contoso中使用动态SQL创建查询,在这种情况下,我正试图通过连接父文件夹的名称(在每个项目上都会发生变化)和表中的文件名(该表的名称在每个项目中也会发生变化)来生成完整的文件路径。我可以在变量中成功地将表的名称传递给我的动态SQL,但我在文件路径中遇到了困难 SELECT CONCAT() 语句,因为Contoso一直试图将此值作为该表的列名读取,而不是作为字符串读取。

    以下是一些示例数据:

    SELECT * INTO AAA_Demo_Table FROM (VALUES ('Image01.png'), ('Image02.png'), ('Report00001.jpg'), ('Image01.jpg'), ('File1.gif')) AS [Filename] ([Filename])
    

    第一个查询是有效的,尽管它显然没有利用我建立的变量:

    DECLARE @DemoTable VARCHAR(200)
    DECLARE @Folder01 VARCHAR(200)
    DECLARE @Folder02 VARCHAR(200)
    DECLARE @Query1 NVARCHAR(MAX)
    
    SET @DemoTable = 'AAA_Demo_Table' -- Replace with the name of your project
    SET @Folder01 = 'Documents'
    SET @Folder02 = 'EMD_Images'
    
    -- THIS EXAMPLE WORKS
    SET @Query1 = '
    SELECT CONCAT(''Documents'', ''/'', ''Images'', ''/'', FileName) AS FilePaths
    FROM AAA_Demo_Table
    '
    
    EXEC sp_executesql @Query1
    

    接下来,如果我尝试动态滑动我的表名,也可以:

    DECLARE @DemoTable VARCHAR(200)
    DECLARE @Folder01 VARCHAR(200)
    DECLARE @Folder02 VARCHAR(200)
    DECLARE @Query1 NVARCHAR(MAX)
    
    SET @DemoTable = 'AAA_Demo_Table' -- Replace with the name of your project
    SET @Folder01 = 'Documents'
    SET @Folder02 = 'Images'
    
    -- THIS EXAMPLE WORKS
    SET @Query1 = '
    SELECT CONCAT(''Documents'', ''/'', ''Images'', ''/'', ADT.FileName) AS FilePaths
    FROM ' + @DemoTable + ' ADT
    '
    
    EXEC sp_executesql @Query1
    

    但是,当我尝试在动态SQL中动态提供文件名时,它失败了:

    DECLARE @DemoTable VARCHAR(200)
    DECLARE @Folder01 VARCHAR(200)
    DECLARE @Folder02 VARCHAR(200)
    DECLARE @Query1 NVARCHAR(MAX)
    
    SET @DemoTable = 'AAA_Demo_Table' -- Replace with the name of your project
    SET @Folder01 = 'Documents'
    SET @Folder02 = 'Images'
    
    -- THIS EXAMPLE FAILS
    SET @Query1 = '
    SELECT CONCAT(' + @Folder01 + ', ''/'', ' + @Folder02 + ', ''/'', ADT.FileName) AS FilePaths
    FROM ' + @DemoTable + ' ADT
    '
    
    EXEC sp_executesql @Query1
    

    enter image description here

    我试着在这里寻找答案,但我没有任何运气。我能找到的所有例子要么没有在内部使用变量 SELECT 语句(它们提供了一个变量 FROM WHERE ,通常),或者他们正在设置整个 选择 将语句转换为变量,而不是将字符串存储到后续的 选择 声明。

    在我的情况下,这是一个更大查询的一小部分,我想对这些文件名进行大量处理,顶级文件夹将被多次引用。拯救整个 选择 将语句转换为单个变量在功能上与让用户滚动查询并进行所有替换没有区别,这就是为什么我希望使用这种方法,即只让用户提供一次表名和顶级文件夹,然后将其应用于以后的查询。

    1 回复  |  直到 6 月前
        1
  •  2
  •   Thom A    6 月前

    只需将参数作为参数传递,不要注入它们。还要对对象名称进行消毒。你面临的是SQL注入攻击。

    DECLARE @DemoTable sysname; --corrected datatype
    DECLARE @Folder01 VARCHAR(200);
    DECLARE @Folder02 VARCHAR(200);
    DECLARE @Query1 NVARCHAR(MAX);
    
    SET @DemoTable = N'AAA_Demo_Table' -- Replace with the name of your project
    SET @Folder01 = 'Documents';
    SET @Folder02 = 'Images';
    
    -- THIS EXAMPLE FAILS
    SET @Query1 = '
    SELECT CONCAT(@Folder01, ''/'', @Folder02, ''/'', ADT.FileName) AS FilePaths
    FROM dbo.' + QUOTENAME(DemoTable) + ' ADT;';
    
    EXEC sys.sp_executesql @Query1, N'@Folder01 varchar(200), @Folder02(200)', @Folder01, @Folder02;