在动态sql中插入记录时如何处理撇号
How to handle apostophee while inserting record in dynamic sal
这里是存储的示例 procedure.Real SP 包含 35 个 parameter.Out 只有一个参数 Message 可以包含撇号。如果我尝试将这样的记录插入 table,让 error.How 来处理它。
Create Procedure ProcInsertRecord
@Name varchar(30),
@mobile_no varchar(30),
@message varchar(30),
@Address varchar(30),
@Designation varchar(30)
as
begin
set @SQL = 'INSERT INTO ['+@table+'](Name,Mobile,Message,Address,Designation) values ('''+@Name +''' , '+@mobile_no+' , '''+@message+''','''+@Address+''','''@Designation+''')
sp_helptext @SQL
end
您丢失了一些字符。
尝试:
DECLARE
@Name VARCHAR(30) = 'Name',
@mobile_no VARCHAR(30) = 'Mobile',
@message VARCHAR(30) = 'Message',
@Address VARCHAR(30) = 'Adress',
@Designation VARCHAR(30) = 'Designation',
@SQL VARCHAR(1000) = 'SQL',
@table VARCHAR(100) = 'table'
SET @SQL = 'INSERT INTO [' + @table + '](Name,Mobile,Message,Address,Designation) values (''' + @Name + ''' , ' + @mobile_no + ' , ''' + @message + ''',''' + @Address + ''',''' + @Designation + ''')'
PRINT @SQL
正如我在评论中所写,对于这个问题,您当前的代码存在几个问题 - 首先,它表明存在数据库设计问题。
除了查找和系统版本控制的 tables,创建多个具有相同结构且仅按名称延迟的 tables 通常表明您正在将元数据与数据 - 意味着数据从您的 tables 内容泄漏到您的 tables 结构。
应消除 table 名称中的差异,并且应将 table 合并为一个 table,包含(至少)一列以表明差异.
尽管如此,有些情况下您根本无法更改数据库结构 - 如果是这种情况,您仍然需要动态 SQL 解决方案。
您的代码的第二个问题是它容易受到 SQL 注入攻击。
如果有人要使用该过程并将最后一个参数值设置为 'bob'');DROP TABLE Students;--'
(或其他一些 table 名称),您的代码将无法阻止该攻击。
此外,您在问题中显示的代码并未在任何地方声明 @table
变量,但我只是假设您在编写问题时错过了这一点。
您抱怨的一个问题(无法使用包含撇号 ('
) 的字符串作为变量)将在您使用 [ 将过程更改为安全执行后得到解决=14=].
只有一条规则可以创建注入安全的动态 SQL,而且它实际上非常简单 - 参数化你可以的,白名单你不能的。
因此,如果我必须为此插入创建一个动态 SQL 存储过程 - 这就是我要做的(另请注意代码中的注释):
CREATE PROCEDURE ProcInsertRecord
@Name varchar(30),
@mobile_no varchar(30),
@message varchar(30),
@Address varchar(30),
@Designation varchar(30),
@table sysname
AS
BEGIN
-- declare your variables. Don't use nvarchar(max) unless you have to.
DECLARE @Sql nvarchar(4000),
@LineBreak nchar(2) = NCHAR(13) + NCHAR(10),
@ParamDefinition nvarchar(4000);
-- White list your table name: making sure not only that it exists,
-- but also it has all the columns you are using in your insert statement.
IF EXISTS(
SELECT 1
FROM InformationSchema.Columns
WHERE Column_Name IN('Name', 'Mobile', 'Message', 'Address', 'Designation')
AND Table_Name = @table
GROUP BY Table_Name
-- This is usually count(distinct xxx), but column names are unique in a table.
HAVING COUNT(Column_Name) = 5
)
BEGIN
-- QUOTENAME protects your query from breaking on table names with spaces or other "strage" chars in their name.
-- Use line breaks to make your query readable.
SET @SQL = N'INSERT INTO '+ QUOTENAME(@table) +' (Name, Mobile, Message, Address, Designation) '+ @LineBreak +
N'VALUES (@Name, @mobile_no, @message, @Address, @Designation)'
-- When dealing with dynamic SQL, print is your best friend.
PRINT @SQL
SET @ParamDefinition =
N'@Name varchar(30),
@mobile_no varchar(30),
@message varchar(30),
@Address varchar(30),
@Designation varchar(30)'
-- Unremark only when print displays a valid SQL.
--EXEC sp_ExecuteSql
-- @SQL,
-- @ParamDefinition,
-- @Name, @mobile_no, @message, @Address, @Designation
END
END
这里是存储的示例 procedure.Real SP 包含 35 个 parameter.Out 只有一个参数 Message 可以包含撇号。如果我尝试将这样的记录插入 table,让 error.How 来处理它。
Create Procedure ProcInsertRecord
@Name varchar(30),
@mobile_no varchar(30),
@message varchar(30),
@Address varchar(30),
@Designation varchar(30)
as
begin
set @SQL = 'INSERT INTO ['+@table+'](Name,Mobile,Message,Address,Designation) values ('''+@Name +''' , '+@mobile_no+' , '''+@message+''','''+@Address+''','''@Designation+''')
sp_helptext @SQL
end
您丢失了一些字符。
尝试:
DECLARE
@Name VARCHAR(30) = 'Name',
@mobile_no VARCHAR(30) = 'Mobile',
@message VARCHAR(30) = 'Message',
@Address VARCHAR(30) = 'Adress',
@Designation VARCHAR(30) = 'Designation',
@SQL VARCHAR(1000) = 'SQL',
@table VARCHAR(100) = 'table'
SET @SQL = 'INSERT INTO [' + @table + '](Name,Mobile,Message,Address,Designation) values (''' + @Name + ''' , ' + @mobile_no + ' , ''' + @message + ''',''' + @Address + ''',''' + @Designation + ''')'
PRINT @SQL
正如我在评论中所写,对于这个问题,您当前的代码存在几个问题 - 首先,它表明存在数据库设计问题。
除了查找和系统版本控制的 tables,创建多个具有相同结构且仅按名称延迟的 tables 通常表明您正在将元数据与数据 - 意味着数据从您的 tables 内容泄漏到您的 tables 结构。
应消除 table 名称中的差异,并且应将 table 合并为一个 table,包含(至少)一列以表明差异.
尽管如此,有些情况下您根本无法更改数据库结构 - 如果是这种情况,您仍然需要动态 SQL 解决方案。
您的代码的第二个问题是它容易受到 SQL 注入攻击。
如果有人要使用该过程并将最后一个参数值设置为 'bob'');DROP TABLE Students;--'
(或其他一些 table 名称),您的代码将无法阻止该攻击。
此外,您在问题中显示的代码并未在任何地方声明 @table
变量,但我只是假设您在编写问题时错过了这一点。
您抱怨的一个问题(无法使用包含撇号 ('
) 的字符串作为变量)将在您使用 [ 将过程更改为安全执行后得到解决=14=].
只有一条规则可以创建注入安全的动态 SQL,而且它实际上非常简单 - 参数化你可以的,白名单你不能的。
因此,如果我必须为此插入创建一个动态 SQL 存储过程 - 这就是我要做的(另请注意代码中的注释):
CREATE PROCEDURE ProcInsertRecord
@Name varchar(30),
@mobile_no varchar(30),
@message varchar(30),
@Address varchar(30),
@Designation varchar(30),
@table sysname
AS
BEGIN
-- declare your variables. Don't use nvarchar(max) unless you have to.
DECLARE @Sql nvarchar(4000),
@LineBreak nchar(2) = NCHAR(13) + NCHAR(10),
@ParamDefinition nvarchar(4000);
-- White list your table name: making sure not only that it exists,
-- but also it has all the columns you are using in your insert statement.
IF EXISTS(
SELECT 1
FROM InformationSchema.Columns
WHERE Column_Name IN('Name', 'Mobile', 'Message', 'Address', 'Designation')
AND Table_Name = @table
GROUP BY Table_Name
-- This is usually count(distinct xxx), but column names are unique in a table.
HAVING COUNT(Column_Name) = 5
)
BEGIN
-- QUOTENAME protects your query from breaking on table names with spaces or other "strage" chars in their name.
-- Use line breaks to make your query readable.
SET @SQL = N'INSERT INTO '+ QUOTENAME(@table) +' (Name, Mobile, Message, Address, Designation) '+ @LineBreak +
N'VALUES (@Name, @mobile_no, @message, @Address, @Designation)'
-- When dealing with dynamic SQL, print is your best friend.
PRINT @SQL
SET @ParamDefinition =
N'@Name varchar(30),
@mobile_no varchar(30),
@message varchar(30),
@Address varchar(30),
@Designation varchar(30)'
-- Unremark only when print displays a valid SQL.
--EXEC sp_ExecuteSql
-- @SQL,
-- @ParamDefinition,
-- @Name, @mobile_no, @message, @Address, @Designation
END
END