VBA SQL 带 WHERE 子句的查询

VBA SQL query with WHERE clause

我正在尝试编写 VBA 代码以将 SQL 数据输入 Excel。除了 WHERE 条件外,一切正常。我认为问题可能出在报价上。这是我的查询:

Sub Engineering_Milestone()

Dim v_project As String
Dim cn  As ADODB.Connection
Dim rs  As ADODB.Recordset
Dim sql As String

Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset

v_project = Worksheets("Parameters").Range("B1").Value

'cn.Open "Provider = x.1; Data Source=x; Initial Catalog=x; Integrated Security=x"


cn.Open "Provider = Sx; Data Source=x; Initial Catalog=x; Integrated Security=x"

Worksheets("Engineering_Milestone").Range("A2:G5000").ClearContents

sql = " SELECT A.ENGINEER_ID, B.[Description], B.BUDGET_APPROVED, A.MILESTONE, A.[DESCRIPTION], A.PCT_COMPLETE, A.SCHEDULE_DATE FROM X as A  Inner Join X as B on A.ENGINEER_ID = B.ENGINEER_ID WHERE B.Project_ID = " & "'" & v_project & "'" and A.Project_ID = " & "'" & v_project & "'"

rs.Open sql, cn

Sheets("Engineering_Milestone").Cells(2, 1).CopyFromRecordset rs

rs.Close
cn.Close

End Sub

当 SQL 查询有一个条件时,它工作正常,即 ...where B.Project_ID = " & "'" & v_project & "'"(没有第二个条件 -> and A.Project_ID = " & "'" & v_project & "'")。

我对此很陌生,如果有人能提供帮助,我将不胜感激...非常感谢。

您只提供了一行代码的一半,所以我只能猜测这就是您的目的:

"where B.Project_ID = '"& v_project &"'& And A.Project_ID = ' & v_project  "'"

当 entering/exiting 多种类型的引号时,字符串可能会令人困惑,但是当您解决构建字符串的问题时,请开始删除所有变量并仅使用硬编码 SQL细绳。

一旦成功,开始一次用变量(和适当的引号)替换值。

切勿编写 SQL 像连接字符串那样的代码。而是简单地使用参数。即:(假设 vProject 是整数)

.. where B.Project_ID = ? And A.Project_ID = ?

cmd.Parameters.Append .CreateParameter("@projectId", adInteger, adParamInput, 0, vProject)
cmd.Parameters.Append .CreateParameter("@projectId", adInteger, adParamInput, 0, vProject)

注意:cmd 是您用于命令的 ADODB.Command 对象。

考虑 SQL 参数化,这是将值传递到 SQL 查询时的行业最佳实践 - 不仅在 VBA 或您的数据库中,而且在 所有 [=18] 中=] 到 any 数据库的语言接口。这个过程更具可读性和可维护性,因为您不再担心报价。另外,代码(SQL 查询)与数据(VBA 变量)分开。

使用 ADO,可以使用 Command Object.

定义和设置参数
Dim v_project As String, sql As String
Dim cn  As New ADODB.Connection
Dim rs  As New ADODB.Recordset
Dim cmd As New ADODB.Command

v_project = Worksheets("Parameters").Range("B1").Value

cn.Open "Provider = Sx; Data Source=x; Initial Catalog=x; Integrated Security=x"

' PREPARED STATEMENT WITH QMARK PLACEHOLDERS
sql = "SELECT A.ENGINEER_ID, B.[Description], B.BUDGET_APPROVED, A.MILESTONE," _
       & "    A.[DESCRIPTION], A.PCT_COMPLETE, A.SCHEDULE_DATE" _
       & " FROM X AS A INNER JOIN X as B ON A.ENGINEER_ID = B.ENGINEER_ID" _
       & " WHERE B.Project_ID = ? AND A.Project_ID = ?"

' COMMAND OBJECT 
Set cmd = New ADODB.Connection

With cmd
    .ActiveConnection = cn    ' CONNECTION OBJECT
    .CommandText = sql
    .CommandType = adCmdText

    ' BINDING PARAMETERS
    .Parameters.Append .CreateParameter("a_projid", adVarChar, adParamInput, , v_project)
    .Parameters.Append .CreateParameter("b_projid", adVarChar, adParamInput, , v_project)
End With

' ASSIGN TO RECORDSET
Set rs = cmd.Execute

With Worksheets("Engineering_Milestone")
     .Range("A2:G5000").ClearContents
     .Cells(2, 1).CopyFromRecordset rs
End With

rs.Close: cn.Close
Set cmd = Nothing: Set rs = Nothing: Set cn = Nothing

正如我所说,永远不要通过字符串连接编写 SQL 代码,使用参数。看到你的代码后,现在更容易了:

Sub Engineering_Milestone()

Dim v_project As String
Dim cn  As ADODB.Connection
Dim rs  As ADODB.Recordset
Dim sql As String
Dim cmd as ADODB.Command

Set cn = New ADODB.Connection

v_project = Worksheets("Parameters").Range("B1").Value

'cn.Open "Provider = x.1; Data Source=x; Initial Catalog=x; Integrated Security=x"


cn.Open "Provider = Sx; Data Source=x; Initial Catalog=x; Integrated Security=x"

Worksheets("Engineering_Milestone").Range("A2:G5000").ClearContents

sql = "SELECT A.ENGINEER_ID, B.[Description], B.BUDGET_APPROVED, " & _
      "   A.MILESTONE, A.[DESCRIPTION], A.PCT_COMPLETE, A.SCHEDULE_DATE" & _
      " FROM X as A" & _
      " Inner Join X as B " & _
      "   on A.ENGINEER_ID = B.ENGINEER_ID and B.Project_ID = A.Project_ID" & _
      " WHERE B.Project_ID = ?"

  set cmd = New ADODB.Command
  cmd.ActiveConnection = cn
  cmd.CommandText = sql
  cmd.Parameters.Append cmd.CreateParameter("@projectId", adVarchar)
  cmd.Parameters("@projectId").Value = v_project

  Set rs = cmd.Execute()

  Sheets("Engineering_Milestone").Cells(2, 1).CopyFromRecordset rs

rs.Close
cn.Close

End Sub

注意:您的 SQL 真的很模糊。您进行自联接只是为了创建某种 笛卡尔联接?可能实际上 engineerId、projectId 组合是唯一的。如果这是正确的,那么您可以简化 SQL:

sql = "SELECT ENGINEER_ID, [Description], BUDGET_APPROVED, " & _
      "   MILESTONE, [DESCRIPTION], PCT_COMPLETE, SCHEDULE_DATE" & _
      " FROM X" & _
      " WHERE Project_ID = ?"