我搜索并搜索了这个答案,我找不到答案。我有一个选中的列表框,用户将选择他们在计算机上遇到的问题。在选中的列表框中,您将看到诸如......慢,病毒,坏硬盘......以及根据他们选择的内容,我将告诉他们估计的维修费用。目前,这是我构建查询的方式:
Dim mIssues As String = ""
For i = 0 To lstIssues.CheckedItemsCount - 1
If mIssues = "" Then
mIssues = String.Format("IssueName = '{0}'", lstIssues.CheckedItems(i))
Else
mIssues = String.Format("{0} OR IssueName = '{1}'", mIssues, lstIssues.CheckedItems(i))
End If
Next
上面的代码将查看他们选择了多少问题。如果他们只选择一个问题,那么它将返回如下字符串:IssueName ='无论他们选择什么'。如果他们选择了多个问题,它将返回如下字符串:IssueName ='无论选择何种'或IssueName ='第二个选择'。因此,如果他们选择多个问题,我会在所有选项之间附加一个OR。我这样做是为了在我的查询中动态构建我的where子句。
这是我的问题:
Dim mySQL As String = "SELECT IssueID, IssueTypeID, IssueName, IssueDescription, " _
& "CustomerID, IndividualCost, GroupCost, Active, ChargeType " _
& "FROM (SELECT IssueID, IssueTypeID, IssueName, IssueDescription, " _
& "CustomerID, IndividualCost, GroupCost, Active, ChargeType " _
& "FROM(cfg_Issues) " _
& "WHERE " & mIssues & " " _
& "GROUP BY IssueID, IssueTypeID, IssueName, IssueDescription, CustomerID, " _
& "IndividualCost, GroupCost, Active) " _
& "ORDER BY IndividualCost DESC, GroupCost ASC;"
正如您可以看到我的where子句来自第一部分代码。我的问题是,有没有更好的方法来做到这一点?我知道必须有一个更好的方法来构建动态where子句查询,我想看看如何。感谢您提供任何可以帮助我的指导。
答案 0 :(得分:7)
这里的第一个问题是对SQL Injection的敞开大门。我希望您可以完全控制lstIssues
中插入的内容,因为在为数据库引擎创建命令时字符串连接始终是一个危险的事情。
使用StringBuilder类实例可以减少您的代码,当您有许多要在字符串中连接的元素时,该实例会有所帮助
Dim mIssues As StringBuilder = new StringBuilder()
For i = 0 To lstIssues.CheckedItemsCount - 1
mIssues.AppendFormat("IssueName = '{0}' OR ", lstIssues.CheckedItems(i))
Next
' I suppose that you have a check in place to not allow to run this query if you don't have at
' least one element checked in the list (if not the WHERE condition will fail)'
mIssues.Length -= 4
这将删除循环中的IF,并且为了删除额外的OR,在退出循环时足以减少StringBuilder实例的长度。
在您的查询文本中,StringBuilder可以使用
mIssues.ToString
您也可以尝试将IN sql子句与此类代码一起使用
Dim mIssues As StringBuilder = new StringBuilder()
For i = 0 To lstIssues.CheckedItemsCount - 1
mIssues.AppendFormat("'{0}', ", lstIssues.CheckedItems(i))
Next
' I suppose that you have a check in place to not allow this query if you don't have at
' least one element checked in the list (if not the WHERE condition will fail)'
mIssues.Length -= 2
mIssues.Insert(0, "IssueName IN(")
mIssues.Append(")")
答案 1 :(得分:0)
我一直希望让SQL为我做所有动态工作。正如许多人所展示的那样,优点是你的所有SQL都是在幕后完成的,并且更安全,无法注入。有些方法可以让邪恶的人实际上(我宁愿不解释黑客本身的细节),将自己的SQL注入你的表单并可能造成大量破坏。
这是动态SQL背后的基本前提(代码可能不准确): 您创建一个基本上编写SQL代码然后执行它的存储过程
CREATE PROCEDURE p_getIssues
as
/*This is where you will place all your input parameters like this
@paramname1 datatype,
@paramname1 datatype,
@mIssues varchar(max) example: virus = 1 and slowcomp = 1
*/
BEGIN
DECLARE @SQL as varchar(max)
SET @SQL = 'SELECT * FROM tablename where ' + @mIssues
EXEC (@SQL)
END
注意:如果你必须调试sproc ...注释掉EXEC并添加一个打印(@SQL) 你可以看到sproc将运行什么SQL。
如果你必须动态,这总是一个首选方法。同样在侧面注意你的VB.NET代码里面的sql不推荐恕我直言,因为从可扩展性和可更新性的角度来看,如果你要添加更多服务,你必须推出新的VB.NET代码。相反,您登录到SQL,您可以进行更改,然后就完成了!