2016-08-11 5 views
0

Using MS Access 2016, ich kopieren eine Abfrage, die ich im Abfrage-Designer zu VBA erstellt, so kann ich die WHERE-Klausel basierend auf einigen Benutzerauswahlen auf einem Formular dynamisch ändern. Diese Abfrage wird dann auf die Datensatzquelle eines Berichts festgelegt.MS Access VBA-Zeichenfolge Verkettung fügt automatisch Wagenrücklauf

Auf dem Formular hat der Benutzer die Möglichkeit, drei Elemente zu konfigurieren: 1) das Datum, 2) System (alle Systeme oder ein bestimmtes), 3) ein Subsystem (alle Subsysteme oder ein bestimmtes). In VBA assembliere ich die Abfrageanweisung mithilfe der Zeichenfolgeverkettung und richte die WHERE-Klausel basierend auf den ausgewählten Optionen ein.

Der Bericht versagte, also begann ich zu untersuchen. Wenn ich die Zeichenkette zum unmittelbaren Fenster (debug.print) drucke, konnte ich ziemlich schnell sehen, was falsch war. Die Zeichenfolge wird bei ungefähr 1138 Zeichen ziemlich lang (Geben oder Nehmen basierend auf den ausgewählten Optionen). Um Zeichen 1027 scheint VBA automatisch einen Zeilenumbruch einzufügen.

Ist das normal? Gibt es einen Weg dahin?

Hier ist meine Code:

'Procedure to execute report 
Private Sub cmdExecReport_Click() 
    On Error GoTo ErrHandler 

    Dim ssql As String 
    Dim ssql2 As String 
    Dim StartDate As Date 
    Dim System As Long 
    Dim SubSystem As Long 


    'Step 1: Acquire data from form 

    'Acquire start date 
    StartDate = Me.txtReportDate_Start.Value 
    'Acquire System 
    System = Me.cboSystem.Value 
    'Acquire SubSystem 
    SubSystem = Me.cboSubSystem.Value 


    'Step 2: Configure record source 

    'Assemble the record source string based on the selected items 
    ssql = "SELECT Reliability_MotorData.DateStamp, Config_BaseData_Motors.Service, Config_BaseData_Motors.SysCapacity_Pct AS [Total Capacity], " 
    ssql = ssql & "Reliability_MotorMasterList.EquipmentName AS Equipment, Config_BaseData_Motors.EquipSystem, Config_BaseData_Motors.EquipSubSystem, " 
    ssql = ssql & "Motor_GetSystemName([Config_BaseData_Motors].[EquipSystem]) AS System, Motor_GetSubSystemName([Config_BaseData_Motors].[EquipSubSystem]) AS [Sub System], " 
    ssql = ssql & "IIf(Motor_GetServiceStatus([Reliability_MotorData].[MotorID],[SelectDate])=-1," & """" & "OOS" & """" & ",IIf(Motor_GetServiceStatus([Reliability_MotorData].[MotorID]," 
    ssql = ssql & "[SelectDate])=0," & """" & "In Service" & """" & "," & """" & "Unknown" & """" & ")) AS [Service Mode], Motor_GetCurrentMotorCapacity([Reliability_MotorData].[MotorID],[SelectDate]) AS [Current Capacity] " 
    ssql = ssql & "FROM (Config_BaseData_Motors RIGHT JOIN Reliability_MotorMasterList ON Config_BaseData_Motors.MotorID = Reliability_MotorMasterList.MotorID) " 
    ssql = ssql & "INNER JOIN Reliability_MotorData ON Reliability_MotorMasterList.MotorID = Reliability_MotorData.MotorID " 

    'Configure the Where clause 
    ssql = ssql & "WHERE ((Reliability_MotorData.DateStamp = #" & StartDate & "#) " 

    'Configure the System list 
    ssql = ssql & "AND ((Config_BaseData_Motors.EquipSystem " 
    'Check the system selected 
    If System = -1 Then 'all systems 
     ssql = ssql & "Like " & """" & "*" & """" & ") " 
    Else 'specific one 
     ssql = ssql & "= " & System 
    End If 
    'Add closing paren 
    ssql = ssql & ") " 


    'Configure the SubSystem list 
    ssql = ssql & "AND ((Config_BaseData_Motors.EquipSubSystem " 
    'Check the subsystem selected 
    If SubSystem = -1 Then 'all subsystems 
     ssql = ssql & " Like " & """" & "*" & """" & ")" 
    Else 'specific one 
     ssql = ssql & "= " & SubSystem 
    End If 

    'Add closing paren & ; 
    ssql = ssql & ");" 

    Debug.Print ssql 

    'Step 3: Launch Report 
    ' DoCmd.OpenReport "Motor Capacity 4", acViewPreview, , , , ssql 

    Exit Sub 

ErrHandler: 
    'Write to event log 
    Call WriteWinEventLog(Error, Now() & " - " & "Execution error on form " & CurrentFormName & " in routine cmdExecReport_Click" & vbCrLf _ 
    & "Error Number: " & Err.Number & vbCrLf & "Source: " & Err.Source & vbCrLf & "Description: " & Err.Description) 

End Sub 

Hier ist das Ergebnis des Druck (Zeilenvorschub für die Sichtbarkeit von Wagenrücklauf ergänzt):

SELECT Reliability_MotorData.DateStamp, Config_BaseData_Motors.Service, Config_BaseData_Motors .SysCapacity_Pct AS [Gesamtkapazität], Reliability_MotorList.EquipmentName AS-Ausrüstung, Config_BaseData_Motors.EquipSystem, Config_BaseData_Motors.EquipSubSystem, Motor_GetSystemName ([Config_BaseData_Motors]. [EquipSystem]) AS-System, Motor_GetSubSystemName ([Config_BaseData_Motors ] [EquipSubSystem]) AS [Subsystem], IIf (Motor_GetServiceStatus ([Zuverlässigkeit_MotorDaten]. [MotorID], [SelectDate]) = - 1, "OOS", IIf (Motor_GetServiceStatus ([Zuverlässigkeit_MotorDaten]. [MotorID], [SelectDate ]) = 0, "In Betrieb", "Unbekannt")) AS [Servicemodus], Motor_GetCurrentMotorCapacity ([Reliability_MotorData]. [MotorID], [SelectDate]) AS [Aktuelle Kapazität] FROM (Config_BaseData_Motors RIGHT JOIN Reliability_MotorMasterList ON Config_BaseData_Motors.MotorID = Reliability_MotorMasterList.MotorID) INNER JOIN Reliability_MotorData ON Reliability_MotorMasterList.MotorID = Reliability_MotorData.MotorID WHERE ((Reliability_MotorData.DateStamp = # 8/10/2016 #)

AND ((Config_BaseData_Motors.EquipSystem Like "")) und ((Config_BaseData_Motors.EquipSubSystem Wie ""));

Ich kann meine Frage ein wenig verkürzen und es in diesem Fall funktioniert, aber was, wenn ich will, damit sie mehr als ein System oder Teilsystem wählen? Irgendwann werde ich anfangen, Charaktere wieder zu verbrauchen und in dasselbe Problem zu laufen.

Gibt es einen besseren Weg, um mein Ziel durch Verkettung zu erreichen? Ich habe versucht, eine große Verkettungsanweisung zu verwenden und eine zweite Zeichenfolgenvariable für die WHERE-Klausel zu verwenden und sie dann zusammen debug.print ssql & ssql2 auszudrucken. Sie alle produzieren das gleiche Ergebnis.

Alternativ, wenn es eine Möglichkeit gibt, eine MS Access-Abfrage dynamisch zu bearbeiten, um die WHERE-Klausel zu ändern; das könnte eine Option sein.

Danke

+0

Haben Sie versucht, Aliase, etw. wie SELECT Feldname AS f FROM Tabellenname t WHERE t.f = 1. Dies wäre eine einfache Möglichkeit, Ihre Abfrage zu verkürzen. Eine andere Möglichkeit wäre, die Abfrage in einer Ansicht zu speichern und die where-Klausel zu verwenden, dh select * from view wo ... –

+0

Sie die Abfragedefinition mit 'Currentdb.QueryDefs (" query_name ") ändern können. SQL =" new SQL "' – winghei

Antwort

0

Best Practice ist nicht SQL-Abfragen in Code zu erstellen, sowieso. Speichern Sie einfach die von Ihnen erstellte Abfrage und verwenden Sie dann ein parametrisiertes Abfragedef, um sie aufzurufen. Z.B.speichern eine Abfrage:

SELECT Reliability_MotorData.DateStamp, 
    Config_BaseData_Motors.Service, 
    Config_BaseData_Motors.SysCapacity_Pct AS [Total Capacity], 
    Reliability_MotorMasterList.EquipmentName AS Equipment, 
    Config_BaseData_Motors.EquipSystem, 
    Config_BaseData_Motors.EquipSubSystem, 
    Motor_GetSystemName([Config_BaseData_Motors].[EquipSystem]) AS System, 
    Motor_GetSubSystemName([Config_BaseData_Motors].[EquipSubSystem]) AS [Sub System], 
    IIf(Motor_GetServiceStatus([Reliability_MotorData].[MotorID], [SelectDate])=-1, 
     "OOS", 
     IIf(Motor_GetServiceStatus([Reliability_MotorData].[MotorID],[SelectDate])=0, 
     "In Service", 
     "Unknown")) AS [Service Mode], 
    Motor_GetCurrentMotorCapacity([Reliability_MotorData].[MotorID],[SelectDate]) AS [Current Capacity] 
FROM (Config_BaseData_Motors 
    RIGHT JOIN Reliability_MotorMasterList 
     ON Config_BaseData_Motors.MotorID = Reliability_MotorMasterList.MotorID) 
    INNER JOIN Reliability_MotorData 
     ON Reliability_MotorMasterList.MotorID = Reliability_MotorData.MotorID 
WHERE ((Reliability_MotorData.DateStamp = [SearchDate]) 
    AND ((Config_BaseData_Motors.EquipSystem Like [SearchSystem])) 
    AND ((Config_BaseData_Motors.EquipSubSystem Like [SearchSubSystem])); 

und QUERY es mag:

Private Sub cmdExecReport_Click() 
    On Error GoTo ErrHandler 

    Dim qdf As QueryDef 
    Dim StartDate As Date 
    Dim System As Long 
    Dim SubSystem As Long 

    'Step 1: Acquire data from form 
    StartDate = Me.txtReportDate_Start.Value 'Acquire start date 
    System = Me.cboSystem.Value 'Acquire System 
    SubSystem = Me.cboSubSystem.Value 'Acquire SubSystem 

    'Step 2: Acquire QueryDef 
    Set qdf = CurrentDB.QueryDefs("qryMyParameterQuery") ' EDIT THIS 

    'Step 3: Substitute Parameters 
    'Substitute date 
    qdf.Parameters("SearchDate") = "#" & StartDate & "#" 

    'Substitute system 
    If System = -1 Then 
     qdf.Parameters("SearchSystem") = """*""" 
    Else 
     qdf.Parameters("SearchSystem") = """" & System & """" ' format as String 
    End If 

    'Substitute subsystem 
    If SubSystem = -1 Then 
     qdf.Parameters("SearchSubSystem") = """*""" 
    Else 
     qdf.Parameters("SearchSubSystem") = """" & SubSystem & """" ' format as String 
    End If 

    ' Step 4: Open report, recordset, etc. 
    ' Example: 
    'Dim rst As Recordset 
    'Set rst = qdf.OpenRecordset() 
    '... 

End Sub 
+0

Danke! Ich habe am Ende eine Kombination aus Ihrer Antwort und dem Kommentar von @winghei oben verwendet. Ich hatte nicht darüber nachgedacht, das Querydef einer vorhandenen Abfrage hinzuzufügen. Mein eventuelles Ziel ist es, dem Benutzer zu ermöglichen, mehrere Elemente aus jeder Liste auszuwählen, und aus irgendeinem Grund würde der Operator "LIKE" keine kommagetrennte Liste akzeptieren. Am Ende benutze ich VBA, um eine benutzerdefinierte 'WHERE'-Klausel am Ende des vorhandenen querydef anzuordnen und hinzuzufügen. – DaveJM