使用 VBA 的 DAO 直通查询:"Error 3131 Syntax error in from clause"

DAO passthrough query using VBA: "Error 3131 Syntax error in from clause"

我复制了一个在 Stack Overflow 中找到的解决方案,并根据我的需要对其进行了调整。

Public Function getAssortmentTypes(Optional personId As Variant) As DAO.Recordset 'personId is integer
    Dim strQuery As String
    Dim qdf As DAO.QueryDef
    Dim rst As DAO.Recordset
    
    If IsMissing(personId) Then
        strQuery = "SELECT assortment_type.type_id, assortment_type.type_name AS qryTest FROM assortment_type"
    Else
        strQuery = "SELECT * FROM get_non_deleted_assortment_types_by_user(" & personId & ")"
    End If
        
    Set qdf = CurrentDb.CreateQueryDef("")
    With qdf
        .SQL = strQuery
        .Connect = getDBConnectionString
        .ReturnsRecords = True
    End With
    
    Set rst = qdf.OpenRecordset
    Debug.Print rst!qryTest
    Set getAssortmentTypes = rst
End Function

在我的 postgresql 数据库中,我确实有一个工作函数和适当的表。我用 DBEaver 测试了 sql 个查询,它们有效。

当我调用不带参数的函数时,我只收到一行(应该是大约 30 行)。

使用参数我希望过滤结果集但收到

"Error 3131 Syntax error in from clause".

始终在 设置 SQL 之前 设置连接字符串。

当您设置 SQL 时,DAO 不知道这将在以后成为直通查询,因此它尝试将其解析为 Access SQL,但显然失败了,因为它是无效访问 SQL.

只需更改顺序:

With qdf
    .Connect = getDBConnectionString
    .ReturnsRecords = True
    .SQL = strQuery
End With

请注意,您应该 ,并且通常在使用外部数据源时使用 ADO 而不是 DAO。 DAO 非常适合 Access,但提供的外部数据源功能较少。例如,ADO 不会在实际需要之前尝试解析 SQL 字符串。

放弃对 DAO 和 QueryDefs 的需要,使用带有命令参数化的 ADO,然后可以将其绑定到记录集:

' SET REFERENCE TO Microsoft ActiveX Data Object #.# Library
Public Function getAssortmentTypes(Optional personId As Variant) As ADODB.Recordset
    Dim conn As ADODB.Connection
    Dim rst As ADODB.Recordset
    Dim cmd As ADODB.Command

    Set conn As New ADODB.Connection
    conn.Open getDBConnectionString

    ' PREPARED STATEMENT WITH QMARKS ?
    If IsMissing(personId) Then
        strQuery = "SELECT assortment_type.type_id, assortment_type.type_name AS qryTest FROM assortment_type"
    Else
        strQuery = "SELECT * FROM get_non_deleted_assortment_types_by_user(?)"
    End If

    Set cmd = New ADODB.Command
    With cmd
        .ActiveConnection = conn
        .CommandText = strQuery
        .CommandType = adCmdText

        '  BIND PARAMETER
        .Parameters.Append .CreateParameter("user_param", adInteger, adParamInput, , personId)

        '  EXECUTE QUERY AND BIND INTO RECORDSET
        Set rst = .Execute
    End With

    Set cmd = Nothing
    Set getAssortmentTypes = rst
End Function

尝试省略“DAO”。在您的 Recordset 和维度语句中添加前缀。更高版本的 Access 了解您的需求。

不推荐引入ADO

问题似乎是您的第一个 SQL 查询将(并且确实)作为 linked table 工作,因此可以工作,因为它不是传递查询.

第二个 sql 失败,因为它仍然尝试使用“访问”sql,而不是 postgresSQL 语法。

我建议您创建一个 PT 查询(使用 Access UI)。在设计器中,确保你 select pass-though:

因此,就像 linked tables - 将连接字符串放入该 PT 查询中。

不要在代码中放置或试图放置连接字符串。因此,您的 re-link 例程还可以包括 re-link PT 查询。

您现在可以使用此代码:

Public Function getAssortmentTypes(Optional personId As Variant) As DAO.Recordset 'personId is integer
   
   Dim rst       As DAO.Recordset
   Dim strQuery  As String
   
   If IsMissing(personId) Then
       strQuery = "SELECT assortment_type.type_id, assortment_type.type_name AS qryTest FROM assortment_type"
   Else
       strQuery = "SELECT * FROM get_non_deleted_assortment_types_by_user(" & personId & ")"
   End If
   
   With CurrentDb.QueryDefs("qryPT")
      .SQL = strQuery
      Set rst = .OpenRecordset
   End With
   
   Debug.Print rst!qryTest
   Set getAssortmentTypes = rst

End Function

因此,创建一个名为(对于此示例)qryPT

的 PT 查询