Query data from SQL to MS Access: Local Tables vs

2019-04-16 14:58发布

问题:

I've created an application that uses the following logic to query data from SQL to my MS Access App.

  1. Using an ODBC connection I execute a stored procedure
  2. Using This is assigned as a Pass-Through Query to pull the data locally.

It looks something like this:

strSQL = "EXEC StoredProcedure " & Variable & "

Call ChangeQueryDef("qryPassThrough", strSQL)
Call SQLPassThrough(strQDFName:="qryPassThrough", _
      strSQL:=strSQL, strConnect:=gODBCConn)

Me.frmDataSheet.Form.RecordSource = "qryPassThrough"

But, recently we have upgraded our SQL Server to 2016 using a high availability failover system - hence our connection string has changed to connect to a listener like so:

gODBCConn = "ODBC;Driver= {SQL Server Native Client 11.0};Trusted_Connection=Yes;Regional=Yes;Database=" & varDB & ";MultiSubnetFailover=Yes;IntegratedSecurity=SSPI;Server=tcp:SERVER_LISTENER,1433;"

However, it looks like using SQL Server Native Client in the connection string is not the same as what we originally had which was SQL Server. Certain data types have changed and do not work in Access.

Is there a better way for me to query data from SQL and persist/display this data in access using ADO or an alternative method?

EDIT Based on Comment:

  • The issue I'm having is that I have tables in SQL using the data type: Decimal(12,2). With some testing and experimenting this seems to fail when using an ODBC pass-through query. But changing the data type to Float seems to work fine. Then there are other datatypes which seem to error too which I've not managed to find yet. It just seems there are a few difference which I'm not aware of and I'm keen to find a better way to load data into my Access App.

EDIT 2 This is the error message I get relating to the data type issue.

回答1:

Sounds like you're not really interested in making the underlying data structure compatible with Access, so:

How to load an ADODB recordset into a datasheet form

Create the form

First, create a datasheet form. For this example, we're going to name our form frmDynDS. Populate the form with 256 text boxes, named Text0 to Text255. To populate the form with the text boxes, you can use the following helper function while the form is in design view:

Public Sub DynDsPopulateControls()
    Dim i As Long
    Dim myCtl As Control
    For i = 0 To 255
        Set myCtl = Application.CreateControl("frmDynDS", acTextBox, acDetail)
        myCtl.NAME = "Text" & i
    Next i
End Sub

VBA to bind a recordset to the form

First, we're going to allow the form to persist, by allowing it to reference itself:

(all on in the code module for frmDynDS)

Public Myself As Object

Then, we're going to add VBA to make it load a recordset. I'm using Object instead of ADODB.Recordset to allow it to both take DAO and ADODB recordsets.

Public Sub LoadRS(myRS As Object)
    Dim i As Long
    Dim myTextbox As textbox
    Dim fld As Object
    i = 0
    With myRS
        For Each fld In myRS.Fields
            Set myTextbox = Me.Controls("Text" & i)
            myTextbox.Properties("DatasheetCaption").Value = fld.NAME
            myTextbox.ControlSource = fld.NAME
            myTextbox.ColumnHidden = False
            i = i + 1
        Next fld
    End With
    For i = i To 255
        Set myTextbox = Me.Controls("Text" & i)
        myTextbox.ColumnHidden = True
    Next i
    Set Me.Recordset = myRS
End Sub

Use the form

(all in the module of the form using frmDynDS)

  1. As an independent datasheet form

    Dim frmDS As New Form_frmDynDS
    frmDS.Caption = "My ADO Recordset"
    frmDS.LoadRS MyAdoRS 'Where MyAdoRS is an open ADODB recordset
    Set frmDS.Myself = frmDS
    frmDS.Visible = True
    frmDS.SetFocus
    

    Note that you're allowed to have multiple instances of this form open, each bound to different recordsets.

  2. As a subform (leave the subform control unbound)

    Me.MySubformControl.SourceObject = "frmDynDS"
    Me.MySubformControl.Form.LoadRS MyAdoRS 'Where MyAdoRS is an open ADODB recordset
    

Warning: Access uses the command text when sorting and filtering the datasheet form. If it contains a syntax error for Access (because it's T-SQL), you will get an error when trying to sort/filter. However, when the syntax is valid, but the SQL can't be executed (for example, because you're using parameters, which are no longer available), then Access will hard crash, losing any unsaved changes and possibly corrupting your database. Even if you disable sorting/filtering, you can still trigger the hard crash when attempting to sort. You can use comments in your SQL to invalidate the syntax, avoiding these crashes.



回答2:

You previously used the pretty ancient, original ODBC Driver for SQL Server simply named SQL Server. You made the right decision to use a newer driver to support your failover cluster. But I would not recommend to use SQL Server Native Client. Microsoft says, It is not recommended to use this driver for new development. Instead I would use the Microsoft ODBC Driver 13.1 for SQL Server. This is the most recent and recommended (by Microsoft) ODBC Driver for SQL Server.

Your main issue seems to be a translation issue between Access and SQL Server via the ODBC layer. So, using the more modern driver might very well make this problem go away. - I do not know if it solves your problem, but this is the very first thing I would try.