I'm new to SQL and recently saw this question, which is described on the [attached picture]
. Any suggestions on how to solve it? Thanks in advance.
In most cases such requirements are better to resolve by starting from the end. Let's try that: "have more than 3 items ... and total price".
select InvoiceId, sum(price)
from InvoiceItem
group by InvoiceId
having count(1) > 3;
This query gives you the overall price for every invoice that has more than 3 items. You might be wondering why there is that funny "having" clause and not the "where" clause.
The database executes first "from" and "where" parts of the query to get the data and only after that using aggregations (sum, count etc.) is possible, so they are to be specified afterwards.
The query above actually returns all the data from requirement, but I assume that whoever gave you this task (that was a teacher, right?) was asking you to retrieve all the data from Invoices table that correspond to the records within the InvoiceItem table that has more than 3 items and so on.
So, for now all you have left is to join the Invoice table with a query from above
select i.id, i.customername, i.issuedate, sum(it.price)
from InvoiceItem it
join Invoice i on it.invoiceid = i.id
group by i.id, i.customername, i.issuedate
having count(1) > 3;
Teacher might ask you why did you use count(1) and not count(*) or count(id) or something. Just tell him/her all these things are equal so you picked just one.
Now it should be working fine presumably. I did not tested it at all as you did not provide the data to test it on and it is late so I am pretty tired. Because of this you might needed to fix some typos or syntax errors I probably made - but hey let's keep in mind you still have to do something on your own with this task.
Related
I am working on a database to track staff productivity. Two of the ways we do that is by monitoring the number of orders they fulfil and by tracking their error rate.
Each order they finish is recorded in a table. In one day they can complete many orders.
It is also possible for a single order to have multiple errors.
I am trying to create a query that provides a summary of their results. This query should have one column with "TotalOrders" and another with "TotalErrors".
I connect the two tables with a LEFT/RIGHT join since not all orders will have errors.
The problem comes when I want to total the number of orders. If someone made multiple mistakes on an order, that order gets counted multiple times; once for each error.
I want to modify my query so that when counting the number of orders it only counts records with distinct OrderID's; yet, in the same query, also count the total errors without losing any.
Is this possible?
Here is my SQL
SELECT Count(tblTickets.TicketID) AS TotalOrders,
Count(tblErrors.ErrorID) AS TotalErrors
FROM tblTickets
LEFT JOIN tblErrors ON tblTickets.TicketID = tblErrors.TicketID;
I have played around with SELECT DISTINCT and UNION but am struggling with the correct syntax in Access. Also, a lot of the examples I have seen are trying to total a single field rather than two fields in different ways.
To be clear when totalling the OrderCount field I want to only count records with DISTINCT TicketID's. When totalling the ErrorCount field I want to count ALL errors.
Ticket = Order.
Query Result: Order Count Too High
Ticket/Order Table: Total of 14 records
Error Table: You can see two errors for the same order on 8th
do a query that counts orders by staff from Orders table and a query that counts errors by staff from Errors table then join those two queries to Staff table (queries can be nested for one long SQL statement)
correlated subqueries
SELECT Staff.*,
(SELECT Count(*) FROM Orders WHERE StaffID = Staff.ID) AS CntOrders,
(SELECT Count(*) FROM Errors WHERE StaffID = Staff.ID) AS CntErrors
FROM Staff;
use DCount() domain aggregate function
Option 1 is probably the most efficient and option 3 the least.
I found a dozen or so different threads that were similar to my question, but I didn't see any that addressed what I am experiencing. I have three databases that keep track of customer/sale transactions. I can join them and get the individual transactions I am looking for without a problem, but when I try to group the results by vendor_name, I get "ORA-00979: not a GROUP BY expression", although vendor_name is one of the columns I am selecting (which I thought was the pre-requisite). Am I overlooking something real simple here?
select tran_date,product_name,quantity,
product_price,vendor_name,quantity*product_price as total
from transactions
join products using(product_num)
join customers using(vendor_id) group by vendor_name;
"Grouping by" vendor name means that you are trying to get one record per vendor name. So, you need to specify how the other columns should be grouped/aggregated.
For example "quantity*product_price", being a number, part of what you need would be
select vendor_name, sum(quantity*product_price)
from transactions
join products using(product_num)
join customers using(vendor_id)
group by vendor_name;
The full answer to your question depends on How you want the other columns to be grouped for a given vendor name.
So I'm taking a course on learning basic SQL (using Oracle), and I felt like I had become fairly fluent with using SELECT statements (grouping, joining, having, etc), but now I'm at a loss on how to deal with this latest problem.
I need to write a statement that would only display rows with more than one piece of data. So, say I had
COMPANY PRODUCT
One Car
One Book
Two Game
it should only list company 'One'. But I can't find anything online to help me.
Select Company
From YourTableName
Group By Company
Having Count(*) > 1
better way to know count of each company is :
Select Company,Count(*)
From Table
Group By Company
Having Count(*) > 1
I have a query as follows in MS Access
SELECT tblUsers.Forename, tblUsers.Surname,
(SELECT COUNT(ID)
FROM tblGrades
WHERE UserID = tblUsers.UserID
AND (Grade = 'A' OR Grade = 'B' OR Grade = 'C')) AS TotalGrades
FROM tblUsers
I've put this into a report and now when trying to view the report it displays an alert "Multi-level GROUP BY clause is not allowed in subquery"
What I dont get is I dont even have any GROUP BY clauses in the query so why is it returning this error?
From Allen Browne's excellent website of Access tips: Surviving Subqueries
Error: "Multi-level group by not allowed"
You spent half an hour building a query with subquery, and verifying it all works. You create a report based on the query, and immediately it fails. Why?
The problem arises from what Access does behind the scenes in response to the report's Sorting and Grouping or aggregation. If it must aggregate the data for the report, and that's the "multi-level" grouping that is not permitted.
Solutions
In report design, remove everything form the Sorting and Grouping dialog, and do not try to sum anything in the Report Header or Report Footer. (In most cases this is not a practical solution.)
In query design, uncheck the Show box under the subquery. (This solution is practical only if you do not need to show the results of the subquery in the report.)
Create a separate query that handles the subquery. Use this query as a source "table" for the query the report is based on. Moving the subquery to the lower level query sometimes (not always) avoids the problem, even if the second query is as simple as
SELECT * FROM Query1;
Use a domain aggregate function such as DSum() instead of a subquery. While this is fine for small tables, performance will be unusable for large ones.
If nothing else works, create a temporary table to hold the data for the report. You can convert your query into an Append query (Append on Query menu in query design) to populate the temporary table, and then base the report on the temporary table.
IMPORTANT NOTE: I'm reposting the info here because I believe Allen Browne explicitly allows it. From his website:
Permission
You may freely use anything (code, forms, algorithms, ...) from these articles and sample databases for any purpose (personal, educational, commercial, resale, ...). All we ask is that you acknowledge this website in your code, with comments such as:
'Source: http://allenbrowne.com
'Adapted from: http://allenbrowne.com
Try this version:
SELECT users.Forename, users.Surname, grades.TotalGrades
FROM tblUsers AS users
LEFT JOIN (SELECT COUNT(ID) as TotalGrades, UserID FROM tblGrades WHERE (Grade = 'A' OR Grade = 'B' OR Grade = 'C') group by userid) AS grades on grades.UserID = users.UserID
I have not tested it. The query itself should be OK, but I'm not sure whether it works in the report data source.
try this:
SELECT users.Forename, users.Surname, count(grades.id) AS TotalGrades
FROM tblUsers AS users
INNER JOIN tblGrades AS grades ON users.ID=grades.UserID
WHERE grades.Grade in ("A","B","C") group by users.ID;
This is a simple joined table. Basically it means. Select all cases where a user has a grade with "A" or "B" or "C" (which would give you a table like this:
user1 | A
user1 | B
user1 | A
user2 | A
...
And then it groups it by users, counting how many times a grade appeared -> giving you the number of grades in the desired range for each user.
I'm taking a database course this semester, and we're learning SQL. I understand most simple queries, but I'm having some difficulty using the count aggregate function.
I'm supposed to relate an advertisement number to a property number to a branch number so that I can tally up the amount of advertisements by branch number and compute their cost. I set up what I think are two appropriate new views, but I'm clueless as to what to write for the select statement. Am I approaching this the correct way? I have a feeling I'm over complicating this bigtime...
with ad_prop(ad_no, property_no, overseen_by) as
(select a.ad_no, a.property_no, p.overseen_by
from advertisement as a, property as p
where a.property_no = p.property_no)
with prop_branch(property_no, overseen_by, allocated_to) as
(select p.property_no, p.overseen_by, s.allocated_to
from property as p, staff as s
where p.overseen_by = s.staff_no)
select distinct pb.allocated_to as branch_no, count( ??? ) * 100 as ad_cost
from prop_branch as pb, ad_prop as ap
where ap.property_no = pb.property_no
group by branch_no;
Any insight would be greatly appreciated!
You could simplify it like this:
advertisement
- ad_no
- property_no
property
- property_no
- overseen_by
staff
- staff_no
- allocated_to
SELECT s.allocated_to AS branch, COUNT(*) as num_ads, COUNT(*)*100 as ad_cost
FROM advertisement AS a
INNER JOIN property AS p ON a.property_no = p.property_no
INNER JOIN staff AS s ON p.overseen_by = s.staff_no
GROUP BY s.allocated_to;
Update: changed above to match your schema needs
You can condense your WITH clauses into a single statement. Then, the piece I think you are missing is that columns referenced in the column definition have to be aggregated if they aren't included in the GROUP BY clause. So you GROUP BY your distinct column then apply your aggregation and math in your column definitions.
SELECT
s.allocated_to AS branch_no
,COUNT(a.ad_no) AS ad_count
,(ad_count * 100) AS ad_cost
...
GROUP BY s.allocated_to
i can tell you that you are making it way too complicated. It should be a select statement with a couple of joins. You should re-read the chapter on joins or take a look at the following link
http://www.sql-tutorial.net/SQL-JOIN.asp
A join allows you to "combine" the data from two tables based on a common key between the two tables (you can chain more tables together with more joins). Once you have this "joined" table, you can pretend that it is really one table (aliases are used to indicate where that column came from). You understand how aggregates work on a single table right?
I'd prefer not to give you the answer so that you can actually learn :)