Excel VBA SQL Join Syntax Error - mysql

I am writing a sub that allows the user to select a Customer from a listbox. The selection is recorded as CustomerID (integer variable) and used to query an Access Database file. The sub should then output to an excel worksheet sales information about the specified customer, notably:
Order Date
OrderID
Total Order Cost (defined as qty sold * Price Sold)
The access file has 3 tables that I need: Customers, Orders, LineItems
My code below should join the customer ID to order ID fields, which is then joined against order ids, and order ids is joined on line items.
' Define SQL statement to get order info for selected product.
SQL = "SELECT O.OrderDate, COUNT(O.OrderID), SUM(L.QuantityOrdered * L.QuotedPrice) AS [TotalCost] " _
& "FROM (((Customers C INNER JOIN Orders O ON C.CustomerID = O.CustomerID) " _
& "INNER JOIN ON O.OrderID = O.CustomerID) INNER JOIN LineItems L " _
& "ON O.OrderID = L.OrderID)" _
& "WHERE O.CustomerID =" & CustomerID & " " _
& "GROUP BY O.OrderDate, O.OrderID" _
& "ORDER BY O.OrderDate"
I keep getting a "Syntax Error in FROM clause". Are my JOIN statements are correct? I have played around with the (), "", etc without success. I have checked and Table Names are correct (Orders, Customers, LineItems) field names are also spelled correctly.

I like to use an array and the Join method with a space delimiter. That makes sure I don't miss any spaces (which #McAdam133 pointed out that you did).
Dim aSql(1 To 6) As String
aSql(1) = "SELECT O.OrderDate, COUNT(O.OrderID), SUM([L.QuantityOrdered]*[L.QuotedPrice]) AS TotalCost"
aSql(2) = "FROM (Customers C INNER JOIN Orders O ON C.CustomerID = O.CustomerID)"
aSql(3) = "INNER JOIN LineItems L ON O.OrderID = L.OrderID"
aSql(4) = "WHERE C.CustomerID = " & CustomerID
aSql(5) = "GROUP BY O.OrderDate"
aSql(6) = "ORDER BY O.OrderDate"
Set rs = CurrentProject.Connection.Execute(Join(aSql, Space(1)))
Here's my advice for inner joins that don't work. Create a Query in Access and look at the SQL it generates. It may not be the prettiest SQL, but it may help you determine what's wrong. If you put Customers, Orders, and LineItems in a query window, draw your arrows if necessary (probably will be there by default), and put a couple of fields in there, Access will generate something like
SELECT Orders.OrderID, Orders.OrderDate, LineItems.QuantityOrdered, LineItems.QuotedPrice
FROM (Customers INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID) INNER JOIN LineItems ON Orders.OrderID = LineItems.OrderID;
That doesn't group anything or use aliases, but it gives you a working statement. Then you can modify with aliases and groupings, testing it along the way.
From your example:
& "FROM (((Customers C INNER JOIN Orders O ON C.CustomerID = O.CustomerID) " _
This line is good. You're joining Customers on Orders using the primary key from Customers and presumably a foreign key in Orders.
& "INNER JOIN ON O.OrderID = O.CustomerID) INNER JOIN LineItems as L " _
I'm not sure what the first join is trying to accomplish, but as #OpiesDad commented it's not what you want. You've already successfully joined Customers and Orders in the first line, so you can take the result of that join and join it up to LineItems (aSql(3) above). The second join (to LineItems) looks fine.
You can join two tables on more than one field. Like if you had two tables of customers and you wanted to see if there is any overlap.
FROM Wholesale INNER JOIN Retail ON Wholesale.CustomerName = Retail.CustName AND Wholesale.State = Retail.StateOrProvince
Based on the structure you've shown, you have nicely unique primary keys in all your tables, so joining on more than one field isn't necessary.
Lastly, you're grouping on OrderID. It's not causing an error, but it's not doing anything either. You use OrderID in an aggregate function in the SELECT portion. You should aggregate the fields you want to aggregate and group by the fields you don't aggregate.

You must use AS when you create an alias for a table in your INNER JOIN's:
' Define SQL statement to get order info for selected product.
SQL = "SELECT O.OrderDate, COUNT(O.OrderID), SUM(L.QuantityOrdered * L.QuotedPrice) AS [TotalCost] " _
& "FROM (((Customers as C INNER JOIN Orders O ON C.CustomerID = O.CustomerID) " _
& "INNER JOIN ON O.OrderID = O.CustomerID) INNER JOIN LineItems as L " _
& "ON O.OrderID = L.OrderID)" _
& "WHERE O.CustomerID =" & CustomerID & " " _
& "GROUP BY O.OrderDate, O.OrderID" _
& "ORDER BY O.OrderDate;"
To be sure, terminate the statement with ;.

The problem you are having is that the join you are trying to do doesn't make sense.
Let's first just get the relevant order and then add the line items as it will make the explanation simpler.
To do this, you want the SQL:
SELECT C.CustomerID, C.CustomerName, O.OrderID, O.OrderDate
FROM Customers C INNER JOIN Orders O ON C.CustomerID = O.CustomerID
WHERE C.CustomerID = 15
ORDER By O.OrderDate
Note, this assumes that the customer you are looking for has ID 15.
This will give you a list of all orders in ascending order for the requested customer.
If you want the line items, then you need to link to this table as well:
SELECT C.CustomerID, C.CustomerName, O.OrderId, O.OrderDate
, SUM(L.QuantityOrdered * L.QuotedPrice) AS [TotalCost]
FROM ((Customers C INNER JOIN Orders O ON C.CustomerID = O.CustomerID)
INNER JOIN LineItems L ON O.OrderID = L.OrderID)
WHERE C.CustomerID = 15
GROUP BY C.CustomerID, C.CustomerName, O.OrderID, O.OrderDate
ORDER BY O.OrderDate
This is likely the query you are looking for. The second INNER JOIN you had listed was superfluous and didn't make sense. You don't want to match the OrderID to the CustomerID, you want the list of orders that match that customer. The first INNER JOIN on C to O already creates this. The where clause limits the customer table to just the one customer.
To put this in your code, just replace the "15" with "CustomerID" from your form.
Also, per McAdam's comment, you are missing spaces in a couple of places. To fix this, I recommend putting all spaces as the beginning of the line so that you can make sure they are there (as is done below). The final code should look like this (removing the customer info from the output):
SQL = "SELECT O.OrderDate, O.OrderID" _
& ", SUM(L.QuantityOrdered * L.QuotedPrice) AS [TotalCost]" _
& " FROM ((Customers C INNER JOIN Orders O ON C.CustomerID = O.CustomerID)" _
& " INNER JOIN LineItems L ON O.OrderID = L.OrderID)" _
& " WHERE O.CustomerID =" & CustomerID _
& " GROUP BY O.OrderDate, O.OrderID" _
& " ORDER BY O.OrderDate"
You also don't seem to actually want the count of orderIDs so I took that out as it also didn't make too much sense.

Related

How to get distinct results using GORM

In Go, I write a query that gives me all data but I just want to data where products.id and clients.id are distinct.
What is the simile query I can write?
res := find.Model(&domain.Clients{}).
Select ("products.id product_id, products.name product_name,"+
" clients.id id, clients.name name, clients.logo, clients.address, "+
"clients.business_id, clients.num_of_employee, clients.email, clients.sns_link, clients.phone").
Joins("LEFT JOIN company_interests ON company_interests.client_id = clients.id").
Joins("LEFT JOIN products ON products.id = company_interests.product_id").
Where("products.id = ? ", productId).Find(&resp)
In Go when i write "Select Distinct" then rest query , it is not valid in go. So, i got an idea to write the query using "group by". In Go "group by" syntax can be used by "GROUP" syntax . So, finally bellow query works fine for me.
res := find.Model(&domain.Clients{}).
Select ("products.id product_id, products.name product_name,"+
" clients.id id, clients.name name, clients.logo, clients.address, "+
"clients.business_id, clients.num_of_employee, clients.email, clients.sns_link, clients.phone").
Joins("LEFT JOIN company_interests ON company_interests.client_id = clients.id").
Joins("LEFT JOIN products ON products.id = company_interests.product_id").
Where("products.id = ? ", productId).
Group("company_interests.client_id, company_interests.product_id" ).Find(&resp)

SQL - Where have i gone wrong

QUESTION: I need to display the customers name and the total cost of the products they have ordered when they exceed over £10.
I cannot tell if it is because I am trying to use an inner join for three tables?
My attempt:
SELECT
DISTINCT Customer.custName,
SUM(Orders.quantity * Product.cost)
FROM
Customer,
Product
INNER JOIN Orders ON Product.productNo = Orders.productNo
WHERE
(Product.productNo = Orders.productNo)
AND (Orders.quantity * Product.cost > 10);
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax. Plus, use GROUP BY. And your JOIN conditions are not complete. So:
SELECT c.custName, SUM(o.quantity * p.cost)
FROM Customer c JOIN
Orders o
ON o.customerNo = c.customerNo JOIN
Product p
ON p.productNo = o.productNo
GROUP BY c.custName
HAVING SUM(o.quantity * p.cost) > 10;

Built in Functions and Grouping is not working in Microsoft Access

I am trying to select from three tables using inner join in Microsoft Access. in one of the fields, i also need to select how many records did it return.
SELECT Person.FirstName, Person.LastName, Person.Phone,
Person.Email,Person.Address, Room.RoomNo, Room.Type, Building.Name,
Floor.Name,count(*) as result
FROM (Floor INNER JOIN (Building INNER JOIN
Room ON Building.BuildingID = Room.BuildingID) ON Floor.FloorNo =
Room.FloorNo) INNER JOIN (Person INNER JOIN Patient ON Person.Username =
Patient.Username) ON Room.RoomNo = Patient.RoomNo
WHERE (((Person.FirstName) Like "*" & [Forms]![search]![firstnameKey] & "*")
AND ((Person.LastName) Like "*" & [Forms]![search]![lastnameKey] & "*")) AND
(patient.status = 1)
GROUP BY Patient.username ;
Any time you have an aggregate function you'll have to group by the fields not being calculated. Just from looking at your select statement you are returning multiple fields, i.e: Person.Firstname, Person.Lastname etc. I believe you will have to group by those non-aggregated fields.
Sample Code:
SELECT Person.FirstName, Person.LastName, Person.Phone, Person.Email, Person.Address, Count(*) as Result <br>
From Table1 join table 2 -- etc <br>
WHERE a = b -- etc <BR>
GROUP BY Person.FirstName, Person.LastName, Person.Phone, Person.Email, Person.Address

SQL Query explanation with IF and INNER JOIN

Could someone please explain this SQL to me, I'm trying to edit code but I don't understand this.
This is the whole sql:
SELECT SQL_CACHE COUNT(c.conversation_id) AS num_messages
FROM table1 AS c
INNER JOIN (
SELECT message_id,conversation_id FROM table2
WHERE recipient_id=:userid ORDER BY created DESC
) AS m ON(m.conversation_id=c.conversation_id)
WHERE (c.initiator_id=:userid OR c.interlocutor_id=:userid)
AND (c.bm_read & IF(c.initiator_id=:userid, :bminit, :bminter)) = 0
AND (c.bm_deleted & IF(c.initiator_id=:userid, :bminit, :bminter)) = 0
GROUP BY c.conversation_id
I don't understand this part:
INNER JOIN (
SELECT message_id,conversation_id FROM table2
WHERE recipient_id=:userid ORDER BY created DESC
) AS m ON(m.conversation_id=c.conversation_id)
WHERE (c.initiator_id=:userid OR c.interlocutor_id=:userid)
AND (c.bm_read & IF(c.initiator_id=:userid, :bminit, :bminter)) = 0
AND (c.bm_deleted & IF(c.initiator_id=:userid, :bminit, :bminter)) = 0
In case you don't understand INNER JOIN, here's a good explanation. It's basically an intersection, produced by doing a CROSS JOIN (i.e. Cartesian Product if you think of the tables as sets) and then filtering based on a condition specified in an ON clause.
The queries are using aliases: c and m respectively to make the overall query shorter. So, c is the result of:
SELECT SQL_CACHE COUNT(c.conversation_id) AS num_messages
FROM table1
and m is the result of:
SELECT message_id,conversation_id FROM table2
WHERE recipient_id=:userid ORDER BY created DESC
and the ON clause is filtering the results of the CROSS JOIN of the two queries based on whether the conversation_id column's value from query c is equal to the conversation_id column's value from query m.
The WHERE, AND and GROUP BY clauses after the INNER JOIN are simply part of the SELECT that are filtering the results after the INNER JOIN occurs.
The IF is pretty simple too:
IF(expr1,expr2,expr3)
If expr1 is TRUE (expr1 <> 0 and expr1 <> NULL) then IF() returns expr2; otherwise it returns expr3.
https://dev.mysql.com/doc/refman/5.1/en/control-flow-functions.html#function_if
Seems like this would do the same thing...
SELECT COUNT(c.conversation_id) num_messages
FROM conv c
JOIN TBL_MSG m
ON m.conversation_id = c.conversation_id
WHERE m.recipient_id = :userid
AND :userid IN (c.initiator_id,c.interlocutor_id)
AND c.bm_read & IF(c.initiator_id=:userid, :bminit, :bminter)) = 0 -- I don't understand
AND c.bm_deleted & IF(c.initiator_id=:userid, :bminit, :bminter)) = 0 -- this bit.
GROUP
BY c.conversation_id
...although you won't know which conversation_id attained which count!?!
It is doing a subquery (after the keywords INNER JOIN), its result is like "a table" but it is created "on the fly", and its alias is "m".
Once you know how this subquery works, you are doing an inner join of your table "c" with the new table "m" joining by keys m.conversation_id and c.conversation_id. So you are joining conversations from different sources.
The where part is just a filter applied to the output, it depends on the content of the fields.
If you have any other question, just leave a comment ;-)

MySql Inner Join Query

I'm using mysql connector to connect visual basic with mysql,i m doing mysql query with 3 tables and i tried with inner join and the "normal mode" with the "normal mode" said not unique table/alias and with inner join the datagrid doesnt load anything,the three table are this ones
Order(N_Order,Date,Client Number)
Line_Order(N_Order,product_code,quantity)
Product(product_code,name,price)
and the mysql query with innerjoin is:
"SELECT c.name, COUNT( b.product_code ) AS cnt FROM order a " & _
"INNER JOIN line_order b ON a.number_order = b.number_order " & _
"INNER JOIN product c ON b.product_code = c.product_code " & _
"GROUP BY c.name " & _
"ORDER BY cnt DESC "
and the normal way is:
"SELECT product.name, COUNT( order_line.product_code ) AS cnt
FROM order, product, order_line where order.number_order = order_line.number_order
AND order_line.product_code = product.product_code
GROUP BY product.name
ORDER BY cnt DESC
LIMIT 0 , 5"
When i run the 2º mysql query in phpmyadmin it works perfectly but when i run it in visual basic it gives me the error not unique tables alias/order i dont know what to do can someone help me please??
Put backticks ` around the table `order` as it conflicts with the reserved keyword in ORDER BY.
Its Solved it was from the datagridview size was too little for the data,2 hours on this because of the datagridview size,thanks guys for the help