Microsoft Visual Basic for Applications
-
SQL LEFT JOIN with GROUP BY, COUNT & WHERE clause
Issue solved: Thanks for sharing the link #Vityata. Given below is the corrected code for others to refer to.
strSQL = "SELECT A.ID, A.Reason, COUNT(B.TimeStamp)" & _
"FROM tblReasons A " & _
"Left Join " & _
"(" & _
"SELECT TimeStamp, Reason FROM tblTracker " & _
"WHERE TimeStamp > #04/11/2017# and TimeStamp < #04/14/2017# " & _
")B ON A.ID = B.Reason " & _
" GROUP BY A.ID, A.Reason"
Do the following.
Go to the immediate window in VBE. (ctrl + G). Then paste the strSQL and press enter on each line. (see the picture below)
Then ask VBE what does it understand by the whole thing, by writing ?strsql and press enter. (see the picture below)
VBE would answer. Inspect the answer.
Put the answer as a query in Access.
Research & find the problem.
In general, I think that GROUP BY and LEFT JOIN are a bit wrong, but I should see the data to tell you more. SQL - Group By with Left Join
Related
I am trying to update a column in my table to specify if the record is a duplicate or not. To do this I added a field called 'DuplicateRecord'.
I can't use the query wizard in access as the duplicate option in this only allows for 10 fields to be checked as a duplicate and my table has more than 10 fields.
The below code works for me:
Call Module1.RunSQL("UPDATE myTable " & _
"SET myTable.DuplicateRecord = TRUE " & _
"WHERE myTable.[CompanyID] IN (" & _
"SELECT * FROM " & _
"(SELECT myTable.[CompanyID] " & _
"FROM myTable " & _
"GROUP BY myTable.[CompanyID] " & _
"HAVING COUNT(*) > 1 ) T1 ) ")
However this code just runs off one field and I need it to run off all fields in the table (there are about 15 fields).
As a test I tried using two fields to see if I could get this working using the following:
Call Module1.RunSQL("UPDATE myTable " & _
"SET myTable.DuplicateRecord = TRUE " & _
"WHERE myTable.[CompanyID] AND myTable.[Product] IN (" & _
"SELECT * FROM " & _
"(SELECT myTable.[CompanyID], myTable.[Product], COUNT(*) " & _
"FROM myTable " & _
"GROUP BY myTable.[CompanyID], myTable.[Product] " & _
"HAVING COUNT(*) > 1 ) T1 ) ")
However I get an error message saying "Run-time error '3306' You have written a subquery that can return more than one field without using the EXISTS reserved word in the main query's FROM clause. Revise the SELECT statement of the subquery to request only one field."
I've tried googling the error but I can't seem to solve it as I don't fully understand it.
Does anyone know how I can apply the logic of testing for duplicates? Is there an easier way to do this then how I am currently trying? I will need to do this for the full record (15 fields), so I am a bit conscious that the way I am currently attempting this might not be the best fit.
I'm trying to attach a SELECT query to a VBA object in Access, but I keep getting the error:
Syntax Error in Join operation
Dim sql As String
sql = "SELECT R_History.iteration, R.RuntimeID, Policylanguage.FormBody " & _
"FROM PolicyLanguage " & _
"INNER JOIN ([Policy&Elements] " & _
"INNER JOIN ((R " & _
"INNER JOIN R_History " & _
"ON (R.RunTimeID = R_History.RunTimeID " & _
"AND (R.ReportID = R_History.ReportID)) " & _
"INNER JOIN StatePolicyLanguage " & _
"ON R_History.Iteration = StatePolicyLanguage.Iteration) " & _
"ON [Policy&Elements].[Text&ElementID] = StatePolicyLanguage.[TextID&ElementID] " & _
"ON PolicyLanguage.TextID = [Policy&Elements].TextID " & _
"WHERE (((R.RuntimeID) = Dlast('runtimeID','r')));"
DoCmd.RunSQL (sql)
I can't get this to run for the absolute life of me. Can anyone tell what's wrong?
Edit: Here is the code I am trying to emulate
If you're running a query where the criteria are values entered in a form (e.g. field1 = frm1.txtValue), you could create a parameterized query where the passed parameters are added to the WHERE clause. That way, you don't have create SQL in VBA---you'd just have to set the parameters in VBA.
As noted by others, Access requires you to put parentheses after each join:
from (((Table1
inner join Table2 on Table2.field1 = Table1.field1)
inner join Table3 on Table3.field2 = Table2.field2)
inner join Table4 on Table4.field3 = Table3.field3)
So, as suggested by others, if you absolutely need to construct the query via VBA, keep your JOIN and ON clauses together to prevent confusion, and add the necessary parentheses.
I've found when you have to create complex queries in Access (either in the SQL editor or in VBA), it can be helpful to write the SQL in a more friendly editor (e.g. Notepad++) that supports things like syntax highlighting. Then, you can paste the query where it needs to go.
Working code sample for SQL SERVER
Select Top 1 bc.Tier_Name, bc.Unit_ID, bc.Name, bc.Description_2
FROM bc_subs as bc INNER JOIN Product_V as v
ON v.ABC = 'ABC: ' + bc.Unit_ID
Problem code sample for Access SQL VBA
"Select Top 1 bc.Tier_Name, bc.Unit_ID, bc.Name, bc.Description_2 " & _
"FROM bc_subs as bc INNER JOIN Product_V as v" & _
"ON v.ABC = " & "ABC: " & "bc.Unit_ID "
In Access, I am trying to INNER JOIN to a table, but part of the join has to concat a string to the front of the value. Table V's key is ABC:123, but the key in BC is just 123 -- so I have to add the ABC: to the font of the 123 to make both sides equal to ABC:123.
I have tried several variations on the VBA Access SQL string but cannot seem to get the join to work correctly.
Any advice? The code was truncated and edited out, variables and alias names changed for safety type reasons. It is the logic I am after within the VBA code and the assignment of a string to a value like this.
You miss a space and some quoting:
"bc.Tier_Name, bc.Unit_ID, bc.Name, bc.Description_2 " & _
"FROM bc_subs as bc INNER JOIN Product_V as v " & _
"ON v.ABC = 'ABC:' + bc.Unit_ID"
The quotes you're using to concatenate, break your string. You can use double quotes to escape them, and get what's functionally equivalent to your SQL server query.
Also, queries using a join with a constant in the on clause in Access should have the on clause surrounded by parentheses to avoid errors in some conditions. I recommend always using them, to be safe.
"Select bc.Tier_Name, bc.Unit_ID, bc.Name, bc.Description_2 " & _
"FROM bc_subs as bc INNER JOIN Product_V as v " & _
"ON (v.ABC = ""ABC: "" & bc.Unit_ID) "
Alternatively, you can write this as a CROSS JOIN:
"Select bc.Tier_Name, bc.Unit_ID, bc.Name, bc.Description_2 " & _
"FROM bc_subs as bc, Product_V as v " & _
"WHERE (v.ABC = ""ABC: "" & bc.Unit_ID) "
I am executing SQL in VB6 and this is the string that I am using, where I define currFA as a number 1. I've been debugging and working at this since it's using inner joins and unions (it's a query I made in Access that I am trying to put into VB6 to run). Right now, I'm getting an operator missing error on the run.
sql = "SELECT DISTINCT [~ALLCBLEQ].Equipment, [~FIRE_AREAS].INDEX" _
& "FROM ([~FIRE_AREAS] INNER JOIN [~ALLTARGETS] ON [~FIRE_AREAS].FULL_ID = [~ALLTARGETS].FA) INNER JOIN ([~ALLRWCBL] INNER JOIN [~ALLCBLEQ] ON" _
& "[~ALLRWCBL].Cable = [~ALLCBLEQ].Cables) ON [~ALLTARGETS].TARGET = [~ALLRWCBL].Cable" _
& "WHERE ((([~FIRE_AREAS].INDEX) = '" & currFA & "'))" _
& "UNION" _
& "SELECT DISTINCT [~ALLCBLEQ].Equipment, [~FIRE_AREAS].INDEX" _
& "FROM [~FIRE_AREAS] INNER JOIN (([~ALLTARGETS] INNER JOIN [~ALLRWCBL] ON [~ALLTARGETS].TARGET=[~ALLRWCBL].Raceway) INNER JOIN [~ALLCBLEQ] ON" _
& "[~ALLRWCBL].Cable=[~ALLCBLEQ].Cables) ON [~FIRE_AREAS].FULL_ID=[~ALLTARGETS].FA" _
& "WHERE ((([~FIRE_AREAS].INDEX) = '" & currFA & "'));"
Any help on the error and syntax improvement tips are greatly appreciated! Still learning!
Thanks!
Your string has no spaces between the lines so when you write:
sql = "SELECT DISTINCT [~ALLCBLEQ].Equipment, [~FIRE_AREAS].INDEX" _
& "FROM ([~FIRE_AREAS] …
That becomes a SQL string like
SELECT DISTINCT [~ALLCBLEQ].Equipment, [~FIRE_AREAS].INDEXFROM ([~FIRE_AREAS] …
Which is obviously invalid SQL because there's no space between INDEX and FROM.
An easy solution is just to put a space before each closing quote (or after each open quote):
sql = "SELECT DISTINCT [~ALLCBLEQ].Equipment, [~FIRE_AREAS].INDEX " _
& "FROM ([~FIRE_AREAS] …
However, If you find yourself writing relatively complex queries like this, I would recommend that you consider converting them to stored procedures or views instead.
I am trying to make a query through a button; though it says
Syntax error in JOIN operation. When I click it... I can't find the syntax error, maybe you guys can help me out? This is the code:
Set qdef = CurrentDb.CreateQueryDef("UnitMoreInfoQ", _
"SELECT UnitsT.*, WorkOrdersQ.CustomerName, WorkOrdersQ.ClientName, WorkOrdersQ.WorkOrderNumber " & _
"FROM UnitsT inner join workordersQ on WorkOrdersT.WorkOrerID=WorkOrdersQ.WorkOrderID " & _
"WHERE UnitsT.UnitID = " & txtWorkOrderID.Value)
The problem seems to be with your JOIN condition:
WorkOrdersT.WorkOrerID=WorkOrdersQ.WorkOrderID
There isn't a WorkOrdersT table or table alias defined in the FROM or other join, so your query isn't valid.
Make it easier on yourself to find and fix SQL errors.
Use a string variable to hold the SQL statement your code constructs. You can Debug.Print that statement before using it with CreateQueryDef. Then when troubleshooting, go to the Immediate window (Ctrl+g) to examine the statement your code is attempting to use. You can copy it from there and then paste it into SQL View of a new query for further testing. And if you need help, show us the completed statement text instead of the VBA code which builds the statement.
Dim strSelect As String
strSelect = "SELECT u.*, w.CustomerName, w.ClientName, w.WorkOrderNumber " & _
"FROM UnitsT As u inner join workordersQ AS w " & _
"on u.WorkOrerID=w.WorkOrderID " & _
"WHERE u.UnitID = " & txtWorkOrderID.Value
Debug.Print strSelect
Set qdef = CurrentDb.CreateQueryDef("UnitMoreInfoQ", strSelect)
Alternatively, use the query designer to create the query you need from scratch. Once you get that working, switch to SQL view, copy the statement text, and revise your VBA code to create the same statement.