How can I fix this syntax error involving the FROM clause? - mysql

I am working on a simple problem set, and I cannot seem to find the issue that is generating this same error: "Syntax Error in FROM Clause".
The question involves the use of various databases in this instant to find "Which employee has sold the most product?"
Here is my code
SELECT (Employees.FirstName + Employees.LastName) as Employee, SUM(Orders.Quantity)
FROM Employees, Orders
JOIN Employees ON Orders.EmployeeID=Employees.EmployeeID
JOIN OrderDetails ON Orders.OrderID=OrderDetails.OrderID
GROUP BY Employee
ORDER BY max(SUM(Quantity)) DESC;
If I am misinterpreting the use of some syntax, please let me know. I am still learning.
Thanks for your help!

When you're using ANSI JOIN you don't list all the tables in the FROM clause. Just list the first table, and the other tables are in JOIN.
You also can't nest aggregate functions as MAX(SUM(Quantity)). If you want to find the employee who sold the most, order by quantity, and use TOP 1 to get the first row.
There's no need to join with OrderDetails, since you're not using anything from that table.
The query should be:
SELECT TOP 1 (Employees.FirstName + Employees.LastName) as Employee, SUM(Orders.Quantity) AS Quantity
FROM Employees
JOIN Orders ON Orders.EmployeeID=Employees.EmployeeID
GROUP BY Employee
ORDER BY Quantity DESC;
Note that if there's a tie for the most sold, this will just show one of them. Getting all of them is more complex, because you need a second query to get that maximum. See sql HAVING max(count()) return zero rows

Related

Trying to average the results of a count which is grouped?

I am using MySQL and am trying to create a query to solve this question:
Average number of borrowed books by occupation
My plan was to count the number of instances of 'BorrowID' because each time a book is borrowed it creates a unique BorrowID. Then group those by clientID so that each person has their total listed books borrowed. Then this is where I start to get lost, as I obviously want to average all the grouped occupations however I am not sure if I am doing that...
First I tried:
SELECT client.Occupation, AVG(BorrowIDCount)
FROM
(
SELECT COUNT(BorrowID) as BorrowIDCount
FROM client, borrower
WHERE client.ClientID = borrower.ClientID
GROUP BY borrower.ClientID
) as x
GROUP BY Occupation
But it gives the error:
Unknown column 'client.Occupation' in 'field list'
Which I thought was because the outer query needed to know which tables...
So then I tried:
SELECT client.Occupation, AVG(BorrowIDCount)
FROM client, borrower
WHERE client.ClientID = borrower.ClientID AND
(
SELECT COUNT(BorrowID) as BorrowIDCount
FROM client, borrower
WHERE client.ClientID = borrower.ClientID
GROUP BY borrower.ClientID
)
GROUP BY Occupation
It didn't like the alias for the subquery so I removed it although no idea why, however it then gave this error:
Unknown column 'BorrowIDCount' in 'field list'
I feel like I may be completely off base in terms of how to create this query but I also feel that I might be close and am just not understanding some rules or syntax here. Any help in the right direction would be incredibly appreciated.
Thanks!
It looks to me like you want to figure out the number of books borrowed by client, then to average that number by occupation. So let's do it in steps:
First is a subquery to get the books per client.
SELECT COUNT(*) borrowed, ClientID
FROM borrower
GROUP BY ClientID
Next, we use that subquery in an outer query to get the average you want.
SELECT AVG(byclient.borrowed) average_borrowed,
client.Occupation
FROM (
SELECT COUNT(*) borrowed, ClientID
FROM borrower
GROUP BY ClientID
) byclient
LEFT JOIN client ON byclient.ClientID = client.ClientID
GROUP BY client.Occupation
ORDER BY AVG(byclient.borrowed) DESC, client.Occupation;
Your requirement calls for an aggregate of an aggregate, so you must nest one aggregate query inside another.
LEFT JOIN allows the inclusion of clients without any occupation. If you don't want that just use JOIN.
The first query in your question failed because your FROM clause referred to a subquery (a virtual table) that lacks the Occupation column. The second one failed because AND (virtual table) doesn't mean anything in SQL.
This nesting of virtual tables is the Structured part of Structured Query Language.

SQL Query: Showing multiple data and total order values

As part of an SQL Queries assignment, I am required to meet the following criteria:
"Display all customers who have bought anything in the last 6 months. Show >customer name, loyalty card number, date of order, and total value of order. >Ensure this is named correctly in the query results as Total_Order_Value."
For this, I came up with a script which has been marked as wrong. I am confused by the feedback as I believe I have met the question criteria.
Find the script and feedback below:
Script
SELECT Aorder.*, Acustomer.*, AorderDetails.quantity, (AorderDetails.quantity *AmenuItem.itemCost) AS Total_Order_Value
FROM Aorder, Acustomer, AmenuItem, AorderDetails
WHERE orderDateTime < Now() AND orderDateTime > DATE_ADD(Now(), INTERVAL -6 MONTH)
AND Acustomer.customerID = Aorder.customerID
AND Aorder.orderID = AorderDetails.orderID
AND AorderDetails.itemID = AmenuItem.itemID
AND Aorder.paymentType IN ('Cash' , 'Card');
Feedback
"At the moment this will multiply cost *qty for each individual item bought in one order. You need the total value for each order. I.e. at the moment I would see a value for each item I bought in one order, I would like to see the total for the whole order. You need to add an aggregate and a group by"
I would appreciate any assistance in helping me understand what went wrong and how I may structure this correctly to meet the requirements.
Thank you in advance.
Essentially, you are reporting results at the orders items level and not customers and orders level as the original question asked. Your current resultset likely repeats customers and order details for each corresponding item which can be lengthy with its one-to-many relationships.
To resolve, simply refactor your SQL statement into an aggregate query that groups on customer and order items and sums each order item's value to retrieve the total amount of whole order. Additionally heed best practices in SQL:
EXPLICIT JOIN: As mentioned in comments do not use the old-join style of commas in FROM clause with matching conditions in WHERE. This is known as implicit joins. The current standard introduced in ANSI-92 emphasizes explicit joins using JOIN and ON clauses. While this does not change efficiency or output, it does aid in readability and maintainability.
SELECT CLAUSE: Try avoiding selecting all fields in tables with Aorder.*, Acustomer.* which is an open-ended resultset output. Your question specifically asked for certain fields: customer name, loyalty card number, date of order, and total value of order. So, select them accordingly.
TABLE ALIASES: For longer table names and tables that share the same prefixes, stems, or suffixes like your A tables, use table aliases that properly abbreviates and defines your identifiers. Again this practice should not change output but aids in readability and maintainability.
See below working SQL statement (adjust field names to actuals).
SELECT c.customer_name,
c.loyalty_card_number,
CAST(o.orderDateTime AS DATE) AS Order_Date,
SUM(d.quantity * m.itemCost) AS Total_Order_Value
FROM Aorder o
INNER JOIN Acustomer c ON c.customerID = o.customerID
INNER JOIN AorderDetails d ON o.orderID = d.orderID
INNER JOIN AmenuItem m ON d.itemID = m.itemID
WHERE o.orderDateTime < Now()
AND o.orderDateTime > DATE_ADD(Now(), INTERVAL -6 MONTH)
AND o.paymentType IN ('Cash' , 'Card')
GROUP BY c.customer_name,
c.loyalty_card_number,
CAST(o.orderDateTime AS DATE)
NOTE: Do not make the mistake as many MySQL users do in excluding non-aggregated columns in GROUP BY clause of an aggregate query which is required in ANSI-SQL. Asterisks, *, should never be used in aggregate queries. MySQL unfortunately allows this feature with its ONLY FULL GROUP BY mode turned off and can return unreliable results.

i want to get all column of Accounts table with this query but it is giving error

select Accounts.name, Accounts.regno Accounts.model , Accounts.slacc, count (servicing.dt) as total
from Accounts l,eft
outer join servicing on Accounts.slacc = servicing.slacc
group by Accounts.slacc,Accounts.name
The error message is
Major Error 0x80040E14, Minor Error 25515
> select Accounts.name,Accounts .model , Accounts.regno, Accounts.slacc, count (servicing.dt) as total from Accounts left outer join servicing on Accounts.slacc = servicing.slacc group by Accounts.slacc,Accounts.name
In aggregate and grouping expressions, the SELECT clause can contain only
aggregates and grouping expressions. [ Select clause = Accounts,model ]
Your query has a group by clause. If you use a group by clause in the query, then every column in the select statement has to do one of two things - either it has to be part of the group by list, or it has to be an aggregate of some kind (Sum, Count, Avg, Max, etc). If you don't do this, SQL doesn't know what to do with the column. In your case Accounts.regno and Accounts.model are listed in the select, but they are not in the group by clause and they are not aggregates - hence your error.
Assume for the moment you have two account records with the same account name and slacc, but different Regno (or model). The group by clause says they have to be joined into one record for display, but you haven't told SQL how to do that. It doesn't matter if the data isn't like that, SQL looks for possible errors first.
In this case, you probably just want all the details grouped. The simplest way is just to make sure you add all the columns needed to the group by, like this
select Accounts.name, Accounts.regno, Accounts.model, Accounts.slacc, count(servicing.dt) as total
from Accounts
left outer join servicing on Accounts.slacc = servicing.slacc
group by Accounts.slacc, Accounts.name, Accounts.regno, Accounts.model
This will fix the error, but does extra grouping you don't need, and would get very cumbersome if you had a lot more columns you wanted from account, as you'd have to add them all. Another way to handle it is to use the minimum amount of columns for the group query, then join the result of that to your main query to get the other columns. This would probably look something like this
select Accounts.name, Accounts.regno, Accounts.model, Accounts.slacc, Totals.Total
from Accounts
left outer join
( Select slacc, count(dt) as total
from servicing
group by slacc
) Totals on Totals.slacc = Accounts.slacc

Analysing multiple rows to determine one status

In one of my tables, some customers have multiple lines - this could be due to re-visits from technicians etc. What I want to do is for each customer ID, analyse whether a re-vist has taken place and place a marker against their name.
I have tried to combine an if/in statement that analyses the max/min visit dates for each customert ID. So if the max>min its classed as a "re-visit", however, i keep getting a syntax error.
Can someone help?
This is a job for two SQL queries:
1st query:
SELECT customerID, count(customerID) as visitCount
FROM tableOfInterest
GROUP BY customerID
2nd query uses first query:
UPDATE customerManifest INNER JOIN queryAbove ON queryAbove.customerID = customerManifest.customerID
SET customerManifest.multipleVisitIndicatorField to queryAbove.visitCount

MySQL grouping error

I'm trying to run a query on a table to see how many unique users have a usage record in the system at a given point. I've been working with the following query, but I've yet to see a proper result.
SELECT count(distinct usageUser), divisionName
FROM records R
INNER JOIN locate L
ON L.computerID=R.usageComputerID
WHERE R.usageWhen LIKE "2012-07-08T12:%"
GROUP BY L.divisionName;
Currently the query returns 18, for each division in the joined table. Without the GROUP BY clause I get the same number of records.
EDIT:
I ran the query again, with suggestions from a comment. By removing the group by and count clause, I get this this (too big to post). This data is very poorly formatted, unfortunately it's inherited and fairly large.
It is not possible for these users to have used every lab like it's listed.
SELECT count(*) cnt, L.divisionName, R.usageUser
FROM records R
INNER JOIN locate L
ON L.computerID=R.usageComputerID
WHERE R.usageWhen LIKE "2012-07-08T12:%"
GROUP BY L.divisionName,R.usageUser;