我有自定义分页,搜索和排序选项的此过程。
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上使用自定义查询处理这样的单引号值?
答案 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