Translating MS Access SQL select query to VBA. Breaks when select with aggregation sum function - sql

Background
I'm trying to use Excel VBA to load data from Microsoft Office Access database.
The code was worked fine and I am now trying to add an extra column Position drawn from the datebasetable named EqBucket into the final result table
The SQL works find in Access but it doesn't parse through to VBA.
The code break when I add in
SUM(Eq_Buckets.Position) AS PositionOfSum
I'm guess it has to do with the aggregation sum wrapped around the column because this issue has never come up with other direct referenced columns.
Appreciate for any pointers. Thanks
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Info:
1. SQL string is stored in Sheets("SQL").Range("A1").value
2. Database tables Eq_SingleName_LBU, Eq_Buckets << this is where the position data are stored
3. Eq_Portfolio_Ref is just a reference table which could be ignored
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
**IF I remove "Sum(Eq_Buckets.Position) AS PositionOfSum" the code works in VBA
Here is the FULLY working SQL code in MS Access:
SELECT Eq_SingleName_LBU.Identifier AS Identifier, Eq_SingleName_LBU.Issuer AS Issuer, Eq_SingleName_LBU.MV_USD AS MV, Sum(Eq_Buckets.Position) AS PositionOfSum, Eq_SingleName_LBU.Issuer_Weight AS [Issuer Weight], Eq_SingleName_LBU.Test_Limit AS Limit, Eq_SingleName_LBU.Room_Limit AS [Remaining Limit], Eq_SingleName_LBU.Data_Date
FROM Eq_SingleName_LBU INNER JOIN (Eq_Buckets INNER JOIN Eq_Portfolio_Ref ON Eq_Buckets.Composite_Portfolio = Eq_Portfolio_Ref.BBG_Account_Codes) ON Eq_SingleName_LBU.Identifier = Eq_Buckets.BB_UniqueID
Where Eq_Buckets.Data_Date = (#03/12/2020#) and Eq_SingleName_LBU.UnderTest="Y"
GROUP BY Eq_SingleName_LBU.Identifier, Eq_SingleName_LBU.Issuer, Eq_SingleName_LBU.MV_USD, Eq_SingleName_LBU.Issuer_Weight, Eq_SingleName_LBU.Test_Limit, Eq_SingleName_LBU.Room_Limit, Eq_SingleName_LBU.Data_Date
HAVING (((Eq_SingleName_LBU.Data_Date) In (#03/12/2020#)))
ORDER BY Eq_SingleName_LBU.Data_Date;
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Here is the VBA code that the SQL string needs to fit through
Sub ADOImportFromAccessTable()
'On Error GoTo ErrorHandler
Application.ScreenUpdating = False
Application.Calculation = xlManual
Sheets("EQ1_SQL").Visible = True
Dim con As Object
Dim rst As Object
Dim dbPath As String
dbPath = "\\Db\Asset_db.accdb"
Set con = CreateObject("ADODB.Connection")
con.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & dbPath
con.Open
Set rst = CreateObject("ADODB.Recordset")
'This is where the SQL code will be referenced.
strSql = ThisWorkbook.Sheets("SQL").Range("A1").Value
Debug.Print strSql
strSql = Replace(strSql, "{date1}", Date_1)
Debug.Print strSql
strSql = Replace(strSql, "{date2}", Date_2)
rst.Open strSql, con, adOpenDynamic, adLockOptimistic
rst.Close
Set rst = Nothing
con.Close
Set con = Nothing
End sub
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Here is the error message I get from Excel VB editor
Here is the error I get from VB editor.
Run-tme error '-2147467259 (80004005);:
Method 'Open' of object' _ Recordset' failed

Try adding brackets around Position ie Sum(B.[Position]),
You can shorten the SQL by using table name aliases, for example
strSQL = " SELECT A.Identifier AS Identifier, A.Issuer AS Issuer, A.MV_USD AS MV," & _
" Sum(B.[Position]) AS PositionOfSum, " & _
" A.Issuer_Weight AS [Issuer Weight]," & _
" A.Test_Limit AS Limit, " & _
" A.Room_Limit AS [Remaining Limit]," & _
" A.Data_Date" & _
" FROM Eq_SingleName_LBU AS A " & _
" INNER JOIN Eq_Buckets AS B" & _
" ON A.Identifier = B.BB_UniqueID" & _
" WHERE B.Data_Date = #2020/12/03# " & _
" AND A.UnderTest = 'Y' " & _
" GROUP BY A.Identifier, A.Issuer," & _
" A.MV_USD, A.Issuer_Weight, A.Test_Limit," & _
" A.Room_Limit, A.Data_Date" & _
" HAVING A.Data_Date IN (#2020/12/03#) " & _
" ORDER BY A.Data_Date"

Related

VBA - Syntax error with TRANSFORM in SQL statement

I'm here to ask you for help because, following various experiments with ADO, I have a problem that I can't solve.
I believe I have done everything right but VBA informs me that I have committed a syntax error in transform education
I have checked everything well and I didn't notice mistakes, also because the same query performed on Access works well.
The purpose is that the query returns this result:
If I run a very similar query without join I have no problems and everything works but if I use the join on the worksheet "months" the syntax problem emerges.
Would you be so kind to suggest where I'm wrong?
Thank you very much for support.
Here the file:
https://www.dropbox.com/s/2isoyahnsmvcr2k/Errore_TRANSFORM.xlsb?dl=0
Here my code:
Sub generaRicavi()
Dim RS As New ADODB.Recordset
Dim conn As String, SQL As String
Application.ScreenUpdating = False
conn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & "; Jet OLEDB:Bypass ChoiceField Validation =True;Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1'"
SQL = "TRANSFORM Sum(Foglio1$.RICAVI)" _
& " SELECT Year([Foglio1$].[DATA])" _
& " FROM MESI$ LEFT JOIN Foglio1$ ON MESI$.MESE = Month([Foglio1$].[DATA])" _
& " GROUP BY Year([Foglio1$].[DATA])" _
& " ORDER BY Year([Foglio1$].[DATA]), MESI$.MESE" _
& " PIVOT MESI$.MESE;"
RS.Open SQL, conn, adOpenStatic, adLockReadOnly
With Foglio2
.Range("A3").CurrentRegion.ClearContents
.Range("A3:M3") = Array("ANNO","GENNAIO", "FEBBRAIO", "MARZO", "APRILE", "MAGGIO", "GIUGNO", "LUGLIO", "AGOSTO", "SETTEMBRE", "OTTOBRE", "NOVEMBRE", "DICEMBRE")
.Range("A4").CopyFromRecordset RS
End With
RS.Close
Application.ScreenUpdating = True
Set RS = Nothing
End Sub
I found the solution.
Indeed there were syntax errors in the query. The square brackets between worksheets and table fields were missing.
The code that works is this:
Sub generaRicavi()
Dim RS As New ADODB.Recordset
Dim conn As String, SQL As String
Application.ScreenUpdating = False
conn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & "; Jet OLEDB:Bypass ChoiceField Validation =True;Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1'"
SQL = "TRANSFORM Sum(Foglio1$.RICAVI)" _
& " SELECT Year([Foglio1$].[DATA])" _
& " FROM [MESI$] LEFT JOIN [Foglio1$] ON [MESI$].[MESE] = Month([Foglio1$].[DATA])" _
& " GROUP BY Year([Foglio1$].[DATA])" _
& " ORDER BY Year([Foglio1$].[DATA]), [MESI$].[MESE]" _
& " PIVOT [MESI$].[MESE];"
RS.Open SQL, conn, adOpenStatic, adLockReadOnly
With Foglio2
.Range("A3").CurrentRegion.ClearContents
.Range("A3:M3") = Array("ANNO", "GENNAIO", "FEBBRAIO", "MARZO", "APRILE", "MAGGIO", "GIUGNO", "LUGLIO", "AGOSTO", "SETTEMBRE", "OTTOBRE", "NOVEMBRE", "DICEMBRE")
.Range("A4").CopyFromRecordset RS
End With
RS.Close
Application.ScreenUpdating = True
Set RS = Nothing
End Sub

ms access vba "Run-time error '3061'. Too few parameters. Expected 7" when querying access query

I google a lot and read all post here related to this issue but found nothing that could give an explanation or help me to resolve this issue.
Following here, a function which work great when the "TableName" parameter is a base table but raise error when it is an ms access view (query). I found nothing yet that could explain this issue as many access query already refer to such views (queries) without issues.
Function DBDistinctCount(FieldName As String, tableName As String) As Long
Dim rs As Recordset, curDb As Database, strSql As String
On Error GoTo ERR_Handling
Set curDb = CurrentDb
'strSql = "SELECT COUNT(PR.[" & FieldName & "]) AS CNT FROM (SELECT [" & FieldName & "] FROM " & TableName & " GROUP BY [" & FieldName & "]) AS PR;"
strSql = "SELECT COUNT(PR." & FieldName & ") AS CNT FROM (SELECT " & FieldName & " FROM " & tableName & " GROUP BY " & FieldName & ") AS PR;"
'strSql = "SELECT COUNT([" & FieldName & "]) AS CNT FROM (SELECT [" & FieldName & "] FROM [" & TableName & "] GROUP BY [" & FieldName & "]);"
'Debug.Print result: SELECT COUNT(PR.ID_Projet) AS CNT FROM (SELECT ID_Projet FROM R_CompilationProjet GROUP BY ID_Projet) AS PR
' Dim qdf As DAO.QueryDef
' Set qdf = curDb.CreateQueryDef(vbNullString, strSql)
Set rs = curDb.OpenRecordset(strSql)
' Set rs = qdf.OpenRecordset(dbOpenSnapshot)
DBDistinctCount = Nz(rs.Fields("CNT"), 0)
ERR_Handling:
If Err.Number <> 0 Then
Dim mess As String
mess = "Erreur vba " & Err.Number & " : " & Err.Description
On Error Resume Next
Call DBHelper.AddLog(mess, "DBDistinctCount")
End If
If Not rs Is Nothing Then rs.Close
Set rs = Nothing
If Not curDb Is Nothing Then curDb.Close
Set curDb= Nothing
End Function
As you can see, I messed up the function a bit in order to find out what could be wrong. I even tried to use a querydef with the same result. I should mention that I've tried to put the resulting sql string itself inside an access query to see exactly the expected result when I ran the query. Any advice would be greatly appreciated.

MS Access: INSERT INTO statement returning a syntax error

I can't figure out the error. I already tried adding more parentheses but this didn't help. This code checks to see if there is already a query called "InsertFilmZip" and if there isn't one, it creates it with the given statement. For some reason, it's saying that there is a Run-time error 3139: Syntax error in PARAMETER clause but I can't find the error.
Private Sub Command8_Click()
Dim dbsCurrent As Database
Set dbsCurrent = CurrentDb
Dim query As QueryDef
Dim sql As String
Dim item_val As String
item_val = Me.Text314
For Each query In CurrentDb.QueryDefs
If query.Name = "InsertFilmZip" Then
Exit For
End If
Next query
If query Is Nothing Then
sql = "parameters " & "P1 Number" & _
"INSERT INTO [tbl_FilmZipInfo] " & _
"(qty_per_unit) " & _
" VALUES ([P1])" & _
"WHERE (((tbl_FilmZipInfo.qty_per_unit)='" & Me.Text314 & "'))"
Set query = CurrentDb.CreateQueryDef("InsertFilmZip", sql)
End If
query.Parameters("P1").Value = Me.Text317
query.Execute
End Sub
Your SQL doesn't make sense, so try this adjustment:
sql = "parameters P1 Long;" & _
"UPDATE [tbl_FilmZipInfo] " & _
"SET qty_per_unit = [P1] " & _
"WHERE qty_per_unit = " & Me.Text314 & ""

Using an ADODB record set to perform a joined update query

In the following code, I would like to join ADODB record set 'rs3' to table 'tblValueChain10' and update 3 different columns based on the values extracted in the ADODB record set 'rs3'. Currently, the update query is not returning anything.
Dim st_Sql3 As String
Dim rs3 As ADODB.Recordset
Set rs3 = New ADODB.Recordset
Dim Max3 As Integer
rs3.Open "SELECT tblRisk05Holding.IDMacroProcesso01, tblRisk05Holding.Level01Risk, Max(tblRisk05Holding.ManualityStatus) AS MaxDiManualityStatus, Max(tblRisk05Holding.RiskProbabilityStatus) AS MaxDiRiskProbabilityStatus, Max(tblRisk05Holding.RiskExposureStatus) AS MaxDiRiskExposureStatus FROM tblRisk05Holding GROUP BY tblRisk05Holding.IDMacroProcesso01, tblRisk05Holding.Level01Risk", CurrentProject.Connection
st_Sql3 = "UPDATE tblValueChain10 INNER JOIN rs3 ON (tblValueChain10.IDMacroProcesso01 = tblRisk05Holding.IDMacroProcesso01) SET L1RiskManuality = " & rs3.Fields(2) & ", L1RiskProbability = " & rs3.Fields(3) & ", L1RiskGravity = " & rs3.Fields(4) & ""
Application.DoCmd.RunSQL (st_Sql2)
rs3.Close
Set rs3 = Nothing
Access never allows you to use a recordset object as a data source in another query. It doesn't matter whether you have an ADO or DAO recordset; you can't do it. And the query type (SELECT, UPDATE, INSERT, etc.) also doesn't matter; you can't use a recordset object as a data source in any query type.
You might get a workable UPDATE by first saving your SELECT statement as a named query, qryRS3. Then revise the UPDATE to INNER JOIN tblValueChain10 to qryRS3. But I'm uncertain whether Access would consider that query to be updatable; the GROUP BY might cause Access to treat it as not updatable. You'll have to test to see.
Although the goal you try to achieve using ADO Recordset in the way presented can't be done (as user #HansUp wrote), you could try the approach with updating your table tblValueChain10 using subquery taken from the rs3 recordset open call.
I hope that the following query :
UPDATE
tblValueChain10
INNER JOIN
(
SELECT
tblRisk05Holding.IDMacroProcesso01,
tblRisk05Holding.Level01Risk,
Max(tblRisk05Holding.ManualityStatus) AS MaxDiManualityStatus,
Max(tblRisk05Holding.RiskProbabilityStatus) AS MaxDiRiskProbabilityStatus,
Max(tblRisk05Holding.RiskExposureStatus) AS MaxDiRiskExposureStatus
FROM
tblRisk05Holding
GROUP BY
tblRisk05Holding.IDMacroProcesso01,
tblRisk05Holding.Level01Risk
) AS qry_Risk05Holding
ON (tblValueChain10.IDMacroProcesso01 = qry_Risk05Holding.IDMacroProcesso01)
SET
tblValueChain10.L1RiskManuality = qry_Risk05Holding.MaxDiManualityStatus,
tblValueChain10.L1RiskProbability = qry_Risk05Holding.MaxDiRiskProbabilityStatus,
tblValueChain10.L1RiskGravity = qry_Risk05Holding.MaxDiRiskExposureStatus
could help you solve your problem.
You should be able to run the above SQL with the following code:
Dim st_Sql3 As String
st_Sql3 = " UPDATE tblValueChain10 INNER JOIN ( "
st_Sql3 = st_Sql3 & " SELECT " _
& " tblRisk05Holding.IDMacroProcesso01, " _
& " tblRisk05Holding.Level01Risk, " _
& " Max(tblRisk05Holding.ManualityStatus) AS MaxDiManualityStatus, " _
& " Max(tblRisk05Holding.RiskProbabilityStatus) AS MaxDiRiskProbabilityStatus, " _
& " Max(tblRisk05Holding.RiskExposureStatus) AS MaxDiRiskExposureStatus "
st_Sql3 = st_Sql3 & " FROM " _
& " tblRisk05Holding " _
& " GROUP BY " _
& " tblRisk05Holding.IDMacroProcesso01, " _
& " tblRisk05Holding.Level01Risk "
st_Sql3 = st_Sql3 & " ) AS qry_Risk05Holding " _
& " ON (tblValueChain10.IDMacroProcesso01 = qry_Risk05Holding.IDMacroProcesso01) " _
& " SET " _
& " tblValueChain10.L1RiskManuality = qry_Risk05Holding.MaxDiManualityStatus, " _
& " tblValueChain10.L1RiskProbability = qry_Risk05Holding.MaxDiRiskProbabilityStatus, " _
& " tblValueChain10.L1RiskGravity = qry_Risk05Holding.MaxDiRiskExposureStatus "
Application.DoCmd.RunSQL (st_Sql3)
The query is being built-up in four stages because as far as I remember there is a restriction in VBA that there can't be too many line breaks _.
Please notice also that the JOIN used in the update query assumes that connecting two tables by IDMacroProcesso01 would ensure that the records are updated in the right way.
I can't check the solution in Acces right now but maybe it could somehow help you, at least a concept. If there were any errors, please write.
You need to loop through the recordset to iteratively update by each record:
Do While NOT rs3.EOF
st_Sql3 = "UPDATE tblValueChain10"_
& " INNER JOIN rs3 ON (tblValueChain10.IDMacroProcesso01 = tblRisk05Holding.IDMacroProcesso01)" _
& " SET L1RiskManuality = " & rs3.Fields(2) & ", L1RiskProbability = " & rs3.Fields(3) & "," _
& " L1RiskGravity = " & rs3.Fields(4) & ""
DoCmd.RunSQL (st_Sql3)
rs3.MoveNext
Loop
Also please note, your RunSQL () command is calling the incorrect SQL string.
If no err appears, then try to place this code:
Set rs3 = New ADODB.Recordset
in form_load, as in,
private sub Form_load()
Set rs3 = New ADODB.Recordset
End Sub
note: this sample is in vb6.0. that's what I can do. Besides, check the version in references

Access VBA query to SQL Server

Hello experts I'm having trouble in my update query from SQL Server. Running first a select query then pass the result to currentdb.execute (to update the table of the access file currently using), using Access vba I'm not doing it right. I really hope you could help me. Maybe you guys know much better way to run my procedure:
connect to sql server 2008, run select query.
pass the result of select query to an access database execute command (or if you have a better idea) to update a table in the current access file that is using.
The error I'm getting to the code is Type mismatch and highlighting .OpenSchema.
These is part of the code that I made wrong (and I really have no idea how to do this).
dbObj.Execute ("UPDATE ACCESS.tbl_Name RIGHT JOIN " & _
conn.OpenSchema(adSchemaTables, Array(Empty, Empty, Empty, "SQLSVR.tbl_Name")) & _
" ON ACCESS.tbl_Name.FieldName_access = " & rst!FieldName_sqlsvr & _
" SET ACCESS.tbl_Name.FieldName_access = " & rst!FieldName_sqlsvr)
These is the whole code.
Option Compare Database
Sub LocalSQLServerConn_Test()
Dim dbOjb As DAO.Database
Dim strDBName As String
Dim strUserName As String
Dim strPassword As String
Set dbObj = CurrentDb()
Set conn = New adodb.Connection
Set rst = New adodb.Recordset
strDBName = "DataSet"
strConnectString = "Provider = SQLOLEDB.1; Integrated Security = SSPI; " & _
"Initial Catalog = " & strDBName & "; Persist Security Info = True; " & _
"Workstation ID = ABCDE12345;"
conn.ConnectionString = strConnectString
conn.Open
strSQL = "SELECT DISTINCT SQLSVR.tbl_Name.FieldName_sqlsvr FROM SQLSVR.tbl_Name"
rst.Open Source:=strSQL, ActiveConnection:=conn, _
CursorType:=adOpenDynamic, LockType:=adLockOptimistic
If rst.RecordCount = 0 Then
MsgBox "No records returned"
Else
rst.MoveFirst
Do While Not rst.EOF
dbObj.Execute ("UPDATE ACCESS.tbl_Name RIGHT JOIN " & _
conn.OpenSchema(adSchemaTables, Array(Empty, Empty, Empty, "SQLSVR.tbl_Name")) & _
" ON ACCESS.tbl_Name.FieldName_access = " & rst!FieldName_sqlsvr & _
" SET ACCESS.tbl_Name.FieldName_access = " & rst!FieldName_sqlsvr)
rst.MoveNext
Loop
End If
conn.Close
rst.Close
Set dbObj = Nothing
End Sub
You should add a linked table (or a pass-through query) to get the data from SQL Server, create an Update Query in your MDB, using a JOIN to update all rows at once (your can use the query designer for this part) and then execute that query using CurrentDb.Execute.