sql-server 逸出存储程序变数中的特殊字符

djmepvbi  于 2022-10-31  发布在  其他
关注(0)|答案(2)|浏览(163)

我已经创建了一个存储过程来练习使用游标,我遇到了特殊字符的问题,例如,如果last_name包含单引号,我就遇到了一个错误,我需要以某种方式对其进行转义,我该怎么做呢?我不知道这些字段中包含哪些特殊字符,我试过使用QUOTENAME(d.last_name),但它不起作用

CREATE OR alter PROCEDURE list_employees
AS
BEGIN 
    DECLARE cursore CURSOR FAST_FORWARD FOR SELECT TOP(20) d.id, d.first_name, d.last_name, cd.contact
          FROM employees d 
          JOIN contacts cd ON cd.fk_employee= d.id
          ORDER BY d.id;
    DECLARE @id_employee VARCHAR(36);
    DECLARE @first_name VARCHAR(50);
    DECLARE @last_name VARCHAR(50);
    DECLARE @contact VARCHAR(255);
    DECLARE @insert_statement varchar(1000);
     IF OBJECT_ID('dbo.list_employees', 'U') IS NOT NULL 
       BEGIN
          DROP TABLE dbo.list_employees; 
       END
    OPEN cursore;
    FETCH NEXT FROM cursore INTO @id_employee , @first_name , @cognome, @contatto ;
    if(@@FETCH_STATUS = 0)
       BEGIN
         CREATE TABLE dbo.list_employees(id_employee VARCHAR(36), first_name VARCHAR(50), last_name VARCHAR(50), contact VARCHAR(255))
       END

    WHILE @@FETCH_STATUS = 0
    BEGIN 
      SET @insert_statement = 'INSERT INTO list_employees SELECT '''+@id_employee +''', '''+@first_name +''', '''+@last_name +''','''+ @contact +''''
     exec(@insert_statement ) 

        FETCH NEXT FROM cursore INTO @id_employee , @first_name , @last_name , @contact ;
        END 
        CLOSE cursore;
        DEALLOCATE cursore;
    END;
ujv3wf0j

ujv3wf0j1#

由于您的代码删除了一个现有的表,然后重新创建它,我怀疑这个过程是一个奇怪的方式来获得“当前前20名”。而不是使用光标和各种麻烦,这将大大简化为使用视图。没有必要不断删除一个表,然后重新填充它。
您的视图可能如下所示。

create or alter view list_employees as
    SELECT TOP(20) d.id
        , d.first_name
        , d.last_name
        , cd.contact
    FROM employees d 
    JOIN contacts cd ON cd.fk_employee = d.id
    ORDER BY d.id;
jw5wzhpr

jw5wzhpr2#

首先,让我们掩盖一下为什么你所拥有的东西不起作用;这是因为你注入了应该是参数的值。2具体来说,这两行是原因:

SET @insert_statement = 'INSERT INTO list_employees SELECT '''+@id_employee +''', '''+@first_name +''', '''+@last_name +''','''+ @contact +''''
exec(@insert_statement )

事实上,这里有两个坏习惯:
1.注入未经整理的值(一个巨大的安全漏洞)
1.使用EXEC(@SQL)语法,而不是sys.sp_executesql,这意味着您 * 不能 * 参数化您的语句。
如果您将语句参数化,那么您遇到的问题就会消失:

SET @insert_statement = 'INSERT INTO dbo.list_employees (id_employee,first_name,last_name,contact) VALUES (@id_employee,@first_name,@last_name,@contact);';
EXEC sys.sp_executesql @insert_statement, N'@id_employee VARCHAR(36),@first_name VARCHAR(50),@last_name VARCHAR(50),@contact VARCHAR(255)', @id_employee,@first_name,@last_name,@contact;

当然,这就提出了一个问题:为什么要使用动态SQL,这个语句没有什么动态的。这并不是说表在执行之前可能不存在,就像表不存在时引擎可以延迟验证一样,而你在同一个作用域中对表进行CREATE。也许表的定义正在改变?我 * 希望 * 不会。
但是,正如前面提到的,这里并不真正需要CURSOR。虽然您声明您正在练习它们,但 * 很少 * 需要它们,并且将这样的东西更改为使用RBAR CURSOR会对性能造成很大影响。您实际上应该使用基于集合的INSERT

INSERT INTO dbo.list_employees (id_employee,first_name,last_name,contact)
SELECT TOP (20)
       e.id,
       e.first_name,
       e.last_name,
       c.contact
FROM dbo.employees e
     JOIN dbo.contacts c ON c.fk_employee= e.id
ORDER BY e.id;

或者,更好的方法是使用VIEW,就像Sean在他们的answer中演示的那样。

相关问题