简体   繁体   English

从Excel VBA运行嵌套的Access SQL查询

[英]Run nested Access SQL Query from Excel VBA

sorry for the title not being as specific as it should be, but english is not my first language and I couldn't explain better. 抱歉,标题不够具体,但是英语不是我的母语,所以我无法更好地解释。 It is NOT a question about how running queries on an Access database from Excel VBA, I know how to do that. 这不是关于如何从Excel VBA在Access数据库上运行查询的问题,我知道该怎么做。 I requesting help because I have a working SQL query built into Access for testing which I need to launch from within a macro enabled Excel spreadsheet. 我之所以寻求帮助,是因为Access中内置了一个有效的SQL查询来进行测试,我需要从启用了宏的Excel电子表格中启动该SQL查询。 The contest: I'm building a tool composed by an Access database (which is "passive", it stores only data) and some Excel spreadsheets interacting with it. 竞赛:我正在构建一个由Access数据库(“被动”,仅存储数据)和一些与其交互的Excel电子表格组成的工具。 I need to it this way because of the users who will have to use it, so I can't change this. 由于需要使用它的用户,我需要这种方式,所以我无法更改它。 I have functions which let me communicate with the DB prebuilding the strings I need. 我有一些函数,可以让我与数据库进行通信,从而预先构建所需的字符串。 In this case I want to read a recordset result of the query. 在这种情况下,我想读取查询的记录集结果。 The VBA function to make this is the following: VBA的功能如下:

Public Function Read_Recordset(ByVal stSQL1 As String) As ADODB.Recordset
Dim cnt As ADODB.Connection
Dim stDB As String
Dim stConn As String
Dim wbBook As Workbook
Dim wsSheet1 As Worksheet

 'Instantiate the ADO-objects.
Set cnt = New ADODB.Connection
Set Read_Recordset = New ADODB.Recordset

 'Path to the database.
stDB = Foglio1.Cells(1, 2)

 'Create the connectionstring.
stConn = "Provider=Microsoft.ACE.OLEDB.12.0;" _
& "Data Source=" & stDB & ";"

With cnt
    .Open (stConn) 'Open the connection.
    .CursorLocation = adUseClient 'Necessary to disconnect the recordset.
End With
Debug.Print stSQL1

With Read_Recordset
    .Open stSQL1, cnt 'Create the recordset.
    Set .ActiveConnection = Nothing 'Disconnect the recordset.
End With

'Release objects from the memory.
cnt.Close
Set cnt = Nothing
End Function

Now, in the Access DB I already built the query I need, which is quite complicated but working flawlessy: 现在,在Access DB中,我已经建立了我需要的查询,这虽然很复杂,但是可以正常工作:

SELECT TOP 2 *
FROM (
SELECT C.Name, format(O.Freight,"#0.00") as Freight, format((O.Forwarding+
C.FixedFee + O.Freight*C.MgmtSurcharge/100 + O.Freight*C.FixedFuelSurcharge/100+(
Switch
(
1.85<C.FuelReferencePrice,
C.FuelReferencePrice,1.85>C.FuelReferencePrice,1.85
)
- C.FuelReferencePrice)/1.85*C.IndexedFuelSurcharge*O.Freight),"#0.00") as
AdditionalCosts,format((O.Freight+(O.Forwarding + C.FixedFee +
O.Freight*C.MgmtSurcharge/100 + O.Freight*C.FixedFuelSurcharge/100+(
Switch
(
1.85<C.FuelReferencePrice,
C.FuelReferencePrice,1.85>C.FuelReferencePrice,1.85
)
- C.FuelReferencePrice)/1.85*C.IndexedFuelSurcharge*O.Freight)),"#0.00") as TotalCost
FROM Temp_TaxableWeights AS T INNER JOIN (Weight_Ranges AS W INNER JOIN (Carriers AS C
INNER JOIN [OBPT_Groupage&LorryOwner] AS O ON C.[ID] = O.[CarrierID]) ON W.ID =
O.WeightRangeID) ON T.CarrierID = C.ID
WHERE (((W.WeightMin)< T.TaxableWeight) AND ((W.WeightMax)>= T.TaxableWeight) AND
((O.DistrictID)=35)) AND O.RateTypeID=4
UNION SELECT C.Name, format(O.Freight*T.TaxableWeight,"#0.00") as Freight,
format((O.Forwarding + C.FixedFee + O.Freight*T.TaxableWeight*C.MgmtSurcharge/100 +
O.Freight*T.TaxableWeight*C.FixedFuelSurcharge/100+(
Switch
(
1.85<C.FuelReferencePrice,
C.FuelReferencePrice,1.85>C.FuelReferencePrice,1.85
)
-C.FuelReferencePrice)/1.85*C.IndexedFuelSurcharge*O.Freight*T.TaxableWeight),"#0.00")
as AdditionalCosts,format((O.Freight*T.TaxableWeight +O.Forwarding + C.FixedFee +
O.Freight*T.TaxableWeight*C.MgmtSurcharge/100 +
O.Freight*T.TaxableWeight*C.FixedFuelSurcharge/100+(
Switch
(
1.85<C.FuelReferencePrice,
C.FuelReferencePrice,1.85>C.FuelReferencePrice,1.85
)
-C.FuelReferencePrice)/1.85*C.IndexedFuelSurcharge*O.Freight*T.TaxableWeight),"#0.00")
as TotalCost
FROM Temp_TaxableWeights AS T INNER JOIN (Weight_Ranges AS W INNER JOIN (Carriers AS C
INNER JOIN [OBPT_Groupage&LorryOwner] AS O ON C.[ID] = O.[CarrierID]) ON W.ID =
O.WeightRangeID) ON T.CarrierID = C.ID
WHERE (((W.WeightMin)< T.TaxableWeight) AND ((W.WeightMax)>= T.TaxableWeight) AND
((O.DistrictID)=35)) AND O.RateTypeID=8
ORDER BY TotalCost ASC
)  AS Best2Quotations;

This gives me the results I want: 这给了我想要的结果:

查询结果

Now my problem. 现在我的问题。 I need to launch this query from an Excel spreadsheet, because it won't be static as I wrote it in Access to test: some of the values are picked up from the sheet itself. 我需要从Excel电子表格中启动此查询,因为它不会像我在Access to test中编写的那样是静态的:某些值是从工作表本身中选取的。 Howevere, I'm not able to run even the static one. 但是,我什至不能运行静态的。 I'm trying with this code: 我正在尝试使用以下代码:

Public Sub btnCalcQuotations_Click()
Dim stSQL As String
Dim rstTemp As ADODB.Recordset
Dim RealWeight As Double, Volume As Double

stSQL = "SELECT TOP 2 * FROM (SELECT C.Name, format(O.Freight," & Chr(34) & "#0.00" & Chr(34) & ") as Freight, format((O.Forwarding + C.FixedFee + O.Freight*C.MgmtSurcharge/100 + O.Freight*C.FixedFuelSurcharge/100+(Switch(1.85<C.FuelReferencePrice,C.FuelReferencePrice , 1.85 > C.FuelReferencePrice, 1.85)" & _
            "- C.FuelReferencePrice)/1.85*C.IndexedFuelSurcharge*O.Freight)," & Chr(34) & "#0.00" & Chr(34) & ") as AdditionalCosts,format((O.Freight+(O.Forwarding + C.FixedFee + O.Freight*C.MgmtSurcharge/100 + O.Freight*C.FixedFuelSurcharge/100+ (Switch(1.85<C.FuelReferencePrice,C.FuelReferencePrice , 1.85 > C.FuelReferencePrice, 1.85)" & _
            "- C.FuelReferencePrice)/1.85*C.IndexedFuelSurcharge*O.Freight))," & Chr(34) & "#0.00" & Chr(34) & ") as TotalCost,W.WeightMin, W.WeightMax, C.FuelReferencePrice,C.IndexedFuelSurcharge FROM Temp_TaxableWeights AS T INNER JOIN (Weight_Ranges AS W INNER JOIN (Carriers AS C INNER JOIN [OBPT_Groupage&LorryOwner] AS O ON C.[ID] = O.[CarrierID])" & _
            "ON W.ID = O.WeightRangeID) ON T.CarrierID = C.ID WHERE (((W.WeightMin) < T.TaxableWeight) And ((W.WeightMax) >= T.TaxableWeight) And ((O.DistrictID) = 35)) And O.RateTypeID = 4 UNION SELECT C.Name, format(O.Freight*T.TaxableWeight," & Chr(34) & "#0.00" & Chr(34) & ") as Freight, format((O.Forwarding + C.FixedFee + O.Freight*T.TaxableWeight*C.MgmtSurcharge/100 +" & _
            "O.Freight*T.TaxableWeight*C.FixedFuelSurcharge/100+ (Switch(1.85<C.FuelReferencePrice,C.FuelReferencePrice , 1.85 > C.FuelReferencePrice, 1.85) - C.FuelReferencePrice)/1.85*C.IndexedFuelSurcharge*O.Freight*T.TaxableWeight)," & Chr(34) & "#0.00" & Chr(34) & ") as AdditionalCosts,format((O.Freight*T.TaxableWeight +O.Forwarding + C.FixedFee + O.Freight*T.TaxableWeight*C.MgmtSurcharge/100 + O.Freight*T.TaxableWeight*C.FixedFuelSurcharge/100+" & _
            "(Switch(1.85<C.FuelReferencePrice,C.FuelReferencePrice, 1.85 > C.FuelReferencePrice, 1.85)- C.FuelReferencePrice)/1.85*C.IndexedFuelSurcharge*O.Freight*T.TaxableWeight)," & Chr(34) & "#0.00" & Chr(34) & ") as TotalCost,W.WeightMin, W.WeightMax, C.FuelReferencePrice, C.IndexedFuelSurcharge FROM Temp_TaxableWeights AS T INNER JOIN (Weight_Ranges AS W INNER JOIN (Carriers AS C INNER JOIN [OBPT_Groupage&LorryOwner] AS O ON C.[ID] = O.[CarrierID]) ON W.ID = O.WeightRangeID) ON T.CarrierID = C.ID" & _
            "WHERE (((W.WeightMin) < T.TaxableWeight) And ((W.WeightMax) >= T.TaxableWeight) And ((O.DistrictID) = 35)) And O.RateTypeID = 8 ORDER BY TotalCost ASC)"
Set rstTemp = Read_Recordset(stSQL)
With rstTemp
    If Not .EOF Then
        r = Application.WorksheetFunction.Match("Trasportatore", Columns(24), 0) + 2
        .MoveFirst
        While Not .EOF
            Cells(r, 24) = !Name
            Cells(r, 25) = !Freight
            Cells(r, 26) = !AdditionalCost
            Cells(r, 27) = !TotalCost
            .MoveNext
        Wend
    End If
End With
End Sub

I can't get it working, in the moment of actually reading the data, so this line of the previous Read_Recordset VBA function: 在实际读取数据的那一刻,我无法使其正常工作,因此,之前的Read_Recordset VBA函数的这一行:

 .Open stSQL1, cnt 'Create the recordset.

it is returning me a runtime error which says: 它返回了一个运行时错误,提示:

"JOIN expression not supported" (or whatever similar, mine is in italian) “不支持JOIN表达式”(或类似名称,我的语言是意大利语)

I'm quite struggling right, after a lot of time spent in buiding the query in Access I couldn't stand the idea of not being able to launch it from Excel. 我很努力,在花费大量时间在Access中建立查询之后,我无法忍受无法从Excel启动查询的想法。 Any suggestions or alternative solution? 有什么建议或替代解决方案吗? Anything would be greatly appreciated. 任何事情将不胜感激。 Regards, 问候,

Marco 马尔科

For future reference, queries built in Access can be activated from ADO as follows (Note: Only need to append parameters if your query actually has them.) 为了将来参考,可以通过以下方式从ADO中激活Access中内置的查询(注意:仅当查询中确实包含参数时,才需要附加参数。)

    'Create Variables
    dim cmd as new adodb.command, cn as new adodb.connection

    'Establish db connection
    cn.connectionstring = "Data Source=MyDataSource.accdb;Provider=Microsoft.ACE.OLEDB.12.0;"
    cn.Open

    'Create and assign parameter values
    Set parStartDate = .CreateParameter("Enter Start Date", adDate, adParamInput, 10)
    Set parEndDate = .CreateParameter("Enter End Date", adVarChar, adParamInput, 10)
        parStartDate.Value = sStartDate
        parEndDate.Value = sEndDate

    'Set up command attribute, assign param objects to command object 
    'so that these are passed through as well

    With cmd
    .CommandType = adCmdStoredProc
    .Parameters.Append parStartDate
    .Parameters.Append parEndDate
    Set .ActiveConnection = cn
    .CommandText = "MyQueryName"
    .Execute
    End With

This will work for an action query in access to enact changes in your DB, but if you need to return a recordset, then just open a recordset as you would normally, but open it with the command object as opposed to an sql string: 这将对访问数据库中的更改进行访问的操作查询起作用,但是如果您需要返回记录集,则只需像往常一样打开记录集,但使用命令对象而不是sql字符串来打开它即可:

rs.Open(cmd)

Hope this helps :) 希望这可以帮助 :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM