我正在一个项目中,我需要创建一个由表组成的动态网页,该表的列结构和数据取决于存储过程选择结果。
以下是要使用的存储过程的示例:
CREATE PROCEDURE dbo.usp_CustomerView
@Address VARCHAR(1000)
AS
SELECT *
FROM Customer
WHERE CustomerAddress LIKE '%' + @Address + '%'
当用户过滤表中的地址列时,此过程有效。
问题是,此过程是静态的。如果我想过滤CustomerName
或CustomerPhone
之类的其他字段,则需要创建另一个参数,然后重新制作该过程。
CREATE PROCEDURE dbo.usp_CustomerView
@Address VARCHAR(1000),
@Name VARCHAR(1000),
@Phone VARCHAR(1000)
AS
SELECT *
FROM Customer
WHERE CustomerAddress LIKE '%' + @Address + '%'
AND CustomerName LIKE '%' + @Name + '%'
AND CustomerPhone LIKE '%' + @Phone + '%'
我正在尝试创建一个动态过程以基于这样的字符串过滤器执行动态SQL查询。
CREATE PROCEDURE dbo.usp_CustomerView
@Filter VARCHAR(MAX)
AS
DECLARE @sql VARCHAR(MAX)
SET @sql = 'SELECT * FROM Customer WHERE ' + @Filter
EXEC @sql
然后像这样从我的网站动态生成一个字符串过滤器。
Dim filterString As String = ""
For Each filter As DataFilter In e.Filter 'Here Filter give Array of filtered user input
If Not String.IsNullOrEmpty(filterString) Then filterString &= " AND "
filterString &= filter.Property & " = '" & filter.Value & "'"
Next
Command.CommandText = "usp_CustomerView @Filter"
Command.Parameters.AddWithValue("@Filter", filterString)
'Read Return Value from Command
这是可行的,但是我很担心安全性,因为它很容易注入。有没有人尝试过创建具有良好安全性的动态where子句?我认为这是常见的事情。但是我找不到任何线索。
有什么建议吗?
更多说明:
此方法的实现实际上更为复杂。我想制作一个动态网页,在该网页中我仅在数据库中设置存储过程的字符串名称,该页面将自动生成一个html表,其结构是通过执行存储过程获得的。所以我不能在页面中放置任何静态查询。
答案 0 :(得分:1)
这在黑暗中有点刺痛,但是表类型呢?然后,您可以以此为基础构建WHERE
子句。就像我说的那样,在黑暗中刺伤,但这至少可以使您走上正确的道路:
USE Sandbox;
GO
CREATE TYPE dbo.WhereClause AS TABLE (ColumnName sysname NOT NULL,
ColumnValue sql_variant NOT NULL);
GO
CREATE PROC dbo.SampleProc @WhereClause WhereClause READONLY AS
BEGIN
DECLARE @SQL nvarchar(MAX);
SET @SQL = N'SELECT *' + NCHAR(10) +
N'FROM Customer'
SET @SQL = @SQL +
ISNULL(NCHAR(10) +N'WHERE' +
STUFF((SELECT NCHAR(10) + N' AND ' + QUOTENAME(WC.ColumnName) + N' LIKE ''%'' + ' + QUOTENAME(CONVERT(varchar(100),ColumnValue),'''') + ' + ''%'''
FROM @WhereClause WC
FOR XML PATH(N'')),1,6,N''),N'') + N';';
PRINT @SQL; --Your best debugging friend (provided you don't go over an nvarchar(4000))
--EXEC sp_executesql @SQL; --Uncomment this to actually run the Dynamic SQL
END
GO
DECLARE @Where WhereClause;
INSERT INTO @Where (ColumnName,
ColumnValue)
SELECT N'CustomerAddress', '123 test street';
INSERT INTO @Where (ColumnName,
ColumnValue)
SELECT N'CustomerName', 'Joe Bloggs';
INSERT INTO @Where (ColumnName,
ColumnValue)
SELECT N'CustomerPhone', '01234 567890';
INSERT INTO @Where (ColumnName,
ColumnValue)
SELECT N'CustomerDOB', CONVERT(date,'19810507');
EXEC dbo.SampleProc @Where;
/*
Returns:
SELECT *
FROM Customer
WHERE [CustomerAddress] LIKE '%' + '123 test street' + '%'
AND [CustomerName] LIKE '%' + 'Joe Bloggs' + '%'
AND [CustomerPhone] LIKE '%' + '01234 567890' + '%'
AND [CustomerDOB] LIKE '%' + 'May 7 1981' + '%';
Note that the date isn't ideal. This *could* be a problem.
*/
DELETE
FROM @Where;
EXEC dbo.SampleProc @Where;
/*
Returns:
SELECT *
FROM Customer;
*/
GO
DROP PROC dbo.SampleProc;
DROP TYPE dbo.WhereClause;
GO
答案 1 :(得分:0)
考虑使用来自受信任源(硬编码或元数据表)的列和参数名称在应用程序代码中构建和执行参数化查询。在这里使用proc几乎没有价值。