2

我已经搜索并搜索了这个问题的答案,但我找不到。我有一个选中的列表框,用户将在其中选择他们在计算机上遇到的问题。在选中的列表框中,您将看到诸如... 慢、病毒、坏硬盘... 并且根据他们选择的内容,我将告诉他们估计的维修费用。目前这是我构建查询的方式:

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 = 'Whatever they selected'。如果他们选择了多个问题,它将返回如下字符串:IssueName = 'Whatever they selected' OR IssueName = 'The second selection'。所以基本上,如果他们选择了多个问题,我将在所有选择之间附加一个 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 子句查询,我想看看如何。感谢您提供任何可以帮助我的指导。

4

2 回答 2

7

这里的第一个问题是SQL 注入的敞开大门。我希望您可以完全控制插入的内容,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(")")
于 2013-05-28T22:00:20.117 回答
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

注意:如果您必须调试存储过程...注释掉 EXEC 并添加一个 PRINT(@SQL),您可以看到存储过程将运行什么 SQL。

如果您必须使用动态,这始终是首选方法。另外,不建议在您的 VB.NET 代码中使用 sql,恕我直言,因为从可扩展性和可更新性的角度来看,如果您要添加更多服务,则必须推出新的 VB.NET 代码。相反,您登录 SQL 并进行更改,然后您就完成了!

于 2013-05-29T05:04:05.677 回答