自定义查询中的单引号

时间:2015-04-08 09:27:59

标签: sql sql-server

我有自定义分页,搜索和排序选项的此过程。

ALTER PROCEDURE [dbo].[stp_OrdersPaginated]
@Name         NVARCHAR(50)=NULL,
@OrderNumber       NVARCHAR(50)=NULL,   
@Status            NVARCHAR(50)=NULL,
@OrderBy           NVARCHAR(100)=NULL,
@PageNumber        INT,            
@PageSize          INT
AS
BEGIN
SET NOCOUNT ON;
CREATE TABLE #ORDERS       
(       
 [OrderId] Bigint
,[Name] Varchar(100)
,[Status] Varchar(50)
,[CreatedDate] Date   
,[OrderNumber] Varchar(100)
,[UserId] Bigint
,[Amount] Decimal
,RowNumber Bigint IDENTITY(1,1)       
)
DECLARE @intTotal INT
SET @intTotal = @PageSize * @PageNumber
DECLARE @sSQL NVARCHAR(MAX)
DECLARE @Where NVARCHAR(MAX) = ''
DECLARE @Order NVARCHAR(MAX) = ''

SET @sSQL = 'SELECT dbo.[Order].OrderId, [User].Name, dbo.[Order].Status, 
                dbo.[Order].CreatedDate, [Order].OrderNumber, dbo.[User].UserId, 
                dbo.Order.[Amount]
        FROM dbo.[Order] 
        INNER JOIN dbo.User 
        ON dbo.[User].UserId = dbo.[Order].UserId'
SET @Order =' ORDER BY ' +@OrderBy


IF @Name is not null
SET @Where = @Where + ' AND dbo.[User].Name LIKE ''%'+@Name+'%'''
IF @OrderNumber is not null
SET @Where = @Where + ' AND dbo.[Order].OrderNumber LIKE '''+@OrderNumber+'%'''
IF @Status is not null
SET @Where = @Where + ' AND dbo.[Order].[Status] LIKE '''+@Status+'%'''

IF LEN(@Where) > 0
SET @sSQL = @sSQL + ' WHERE ' + RIGHT(@Where, LEN(@Where)-4)

INSERT INTO #ORDERS
EXECUTE (@sSQL + @Order)

Select [OrderId],[Name],[Status],[CreatedDate],[OrderNumber,[UserId]
,[Amount],RowNumber
From #ORDERS           
WHERE  RowNumber between ((@PageNumber * @PageSize)-(@PageSize- 1)) AND (@PageNumber * @PageSize) 

Declare @TotalRecords Integer             
Declare @TotalPage Integer                         

SELECT @TotalRecords=MAX(RowNumber) from #ORDERS              
if(@TotalRecords is not NULL)             
begin             
if(@TotalRecords%@PageSize = 0)             
begin             
SET @TotalPage = @TotalRecords/@PageSize             
end             
else              
begin             
SET @TotalPage = @TotalRecords/@PageSize + 1             
end             
end             
else             
begin             
set @TotalPage = 1             
end              
Select @TotalPage [TotalPages], @TotalRecords [TotalRecords]
DROP Table #ORDERS
END

正如您所看到的,其中一个搜索参数是名称。由于显而易见的原因,该程序适用于除单引号(')之外的所有程序。例如:如果我通过奥布赖恩的名字就会失败。有没有办法在SQL Server上使用自定义查询处理这样的单引号值?

2 个答案:

答案 0 :(得分:1)

您的问题源于不以最佳实践方式构建动态SQL,这使得构建正确的SQL变得困难,也会使您暴露于SQL注入攻击。

基本上,在向SQL字符串添加参数时,绝不应使用连接。我还使用char(37)来表示%符号,因为这样就没有必要用撇号来转义它。

所以你的SQL就像

IF @Name is not null
  SET @Where += 'AND Name LIKE char(37)+@Name+char(37)'

IF @OrderNumber is not null
  SET @Where += ' AND OrderNumber LIKE @OrderNumber+char(37)'

IF @Status is not null
  SET @Where += ' AND [Status] LIKE @Status+char(37)'

IF LEN(@Where) > 0
  SET @sSQL += ' WHERE ' + RIGHT(@Where, LEN(@Where)-4)

创建OrderBy更难,因为您无法对其进行参数化。如果你绝对信任传入的值,那么你的代码是可以的,但最安全的方法是使用类似if语句的东西  测试传入的值并创建适当的子句。 e.g。

IF @OrderBy = 'status'
  SET @Ssql += ' ORDER BY Status'

--Next you need to declare the parameters being included in the dynamic SQL. i'm making up the variable types, as you didn't specify what they were.
declare @params nvarchar(1000) = '@name nvarchar(100), @ordernumber nvarchar(100), @status nvarchar(10)'

--Then you can execute your dynamic SQL, passing to it the parameters provided to your procedure

insert into #temp 
ExeCUTE sp_executesql @sSQL, @params,  @name, @ordernumber, @status

以这种方式构建动态SQL而不是连接字符串的另一个好处是,SQL Server实际上可以像对非动态SQL一样缓存查询计划,并且您没有获得性能影响。你使用串联。

答案 1 :(得分:0)

尝试:

IF @Name is not null
BEGIN
   SET @Name = REPLACE(@Name, '''', '''''')
   SET @Where = @Where + ' AND dbo.[User].Name LIKE ''%'+@Name+'%'''
END