Ok, I have three tables: theater, spectacles and tickets. A theater has one or more spectacles and for a spectacle were sold one or more tickets* So, id_theater is foreign key in TABLE SPECTACLES and id_spectacle is foreign key in TABLE TICKETS. In table TICKETS, I have ticket_price and id_ticket and with count(id_ticket) I calculate the number of tickets sold for spectacles. And each theater has one or more spectacles. The value for spectacles is calculated as: count(tickets.id_ticket) * tickets.ticket_price. After I calculate the value for spectacles, I need to gather the value of spectacles to find the each value of theater and for this I use SUM().
I need to write a query where I need to calculate the total value obtained by each theater and to be sort by value. For this I need to use the SUM() function. I tried so many different options, but I have different errors. When I tried to run this, this error appeared :
SQL Error: ORA-00937: not a single-group group function
SELECT
theater.id_theater,
SUM(count(tickets.id_ticket) * tickets.id_ticket) total_theater
FROM spectacles, theater
GROUP BY theater.id_theater
ORDER BY total_theater DESC;
For this problem I must use SUM, but I really don't know what do to at this point and would appreciate any help.
You can use normal INNER JOIN and sum as follows:
SELECT theater.id_theater,
SUM(tkt.ticket_price) total_theater_tkt_price
FROM spectacles s
join theater t on t.id_theatre = s.id_theatre
JOIN tickets tkt on tkt.id_spectacle = s.id_spectacle
GROUP BY t.id_theater
ORDER BY total_theater_tkt_price DESC;
Note: Always use the standard ANSI-JOINS.
Related
Q1: After using the Group By function, why does it only output one row of each group at most? Does this mean that having is supposed to filter the group rather than filter the records in each group?
Q2: I want to find the records in each group whose ages are greater than the average age of that group. I tried the following, but it returns nothing. How should I fix this?
SELECT *, avg(age) FROM Mytable Group By country Having age > avg(age)
Thanks!!!!
You can calculate the average age for each country in a subquery and join that to your table for filtering:
SELECT mt.*, MtAvg.AvgAge
FROM Mytable mt
inner join
(
select mtavgs.country
, avg(mtavgs.age) as AvgAge
from Mytable mtavgs
group by mtavgs.country
) MTAvg
on mtavg.country=mt.country
and mt.Age > mtavg.AvgAge
GROUP BY returns always 1 row per unique combination of values in the GROUP BY columns listed (provided that they are not removed by a HAVING clause). The subquery in our example (alias: MTAvg) will calculate a single row per country. We will use its results for filtering the main table rows by applying the condition in the INNER JOIN clause; we will also report that average by including the calculated average age.
GROUP BY is a keyword that is called an aggregate function. Check this out here for further reading SQL Group By tutorial
What it does is it lumps all the results together into one row. In your example it would lump all the results with the same country together.
Not quite sure what exactly your query needs to be to solve your exact problem. I would however look into what are called window functions in SQL. I believe what you first need to do is write a window function to find the average age in each group. Then you can write a query to return the results you need
Depending on your dbms type and version, you may be able to use a "window function" that will calculate the average per country and with this approach it makes the calculation available on every row. Once that data is present as a "derived table" you can simply use a where clause to filter for the ages that are greater then the calculated average per country.
SELECT mt.*
FROM (
SELECT *
, avg(age) OVER(PARTITION BY country) AS AvgAge
FROM Mytable
) mt
WHERE mt.Age > mt.AvgAge
New to BigQuery and SQL (and Stack Overflow), spent hours and couldn't find a solution on the web and couldn't figure it out myself. Would really appreciate if someone could shed some light:
Data Source from BigQuery: bigquery-public-data.new_york.citibike_stations
Screenshot of the table named "citibike_stations" showing 1623 rows.
The next screenshot shows that the table has a column named "num_bikes_available", which I used in my query.
Screenshot showing that the "citibike_stations" table has a column named "num_bikes_available"
I queried the following:
SELECT
station_id,
num_bikes_available,
AVG(num_bikes_available) AS avg_num_bikes_available
FROM
bigquery-public-data.new_york.citibike_stations;
Error Message: SELECT list expression references column station_id which is neither grouped nor aggregated at [2:3]
So I added a "GROUP BY" clause at the end:
SELECT
station_id,
num_bikes_available,
AVG(num_bikes_available) AS avg_num_bikes_available
FROM
bigquery-public-data.new_york.citibike_stations
GROUP BY
station_id, num_bikes_available;
The result I got is not what I wanted, which is shown in the following screenshot:
Screenshot of the query result, but not the desired result.
Someone else did the following query and was able to get it right (using a subquery):
SELECT
station_id,
num_bikes_available,
(SELECT AVG(num_bikes_available)
FROM bigquery-public-data.new_york.citibike_stations) AS avg_num_bikes_available
FROM
bigquery-public-data.new_york.citibike_stations;
Screenshot of the correct result ↓:
Screenshot of the correct result
Questions:
Why wouldn't it work when the "AVG(num_bikes_available) AS avg_num_bikes_available" is in the "SELECT" statement, as shown in the first set of query?
Why did it work when the "(SELECT AVG(num_bikes_available) FROM bigquery-public-data.new_york.citibike_stations) AS avg_num_bikes_available" is nested in the SELECT statement, as shown in the last set of query? Why does it not ask for aggregation when the "(SELECT AVG(num_bikes_available) FROM bigquery-public-data.new_york.citibike_stations) AS avg_num_bikes_available" is nested within the SELECT statement?
SELECT
station_id,
num_bikes_available,
AVG(num_bikes_available) OVER() AS avg_num_bikes_available
FROM
bigquery-public-data.new_york.citibike_stations;
You are confusing how aggregation works. I think it would be easier if you tried to express the query in a sentence.
What you want is 'A list of all the available stations along with information about the number of bikes in each station and the average number of bikes available in all stations'.
Note that the average is just one value, the total number of available bikes in all stations divided by the number of stations. This is the reason why the independant query actually works for what you want.
The 'group by' indicates which rows of the initial table will create each group/row of the result. In your case you want the average of the whole table, so when the query is expressed properly there are no groups to be defined.
If your table had multiple entries per city for example, you could do the average grouped by city to find the average number of available bikes in the stations of each city. Note that the select would be able to return the city and the average, but not any other attribute, e.g. the station id as they wouldn't make sense within each group.
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 have a table with several "ticket" records in it. Each ticket is stored by day (i.e. 2011-07-30 00:00:00.000) I would like to count the unique records in each month by year I have used the following sql statement
SELECT DISTINCT
YEAR(TICKETDATE) as TICKETYEAR,
MONTH(TICKETDATE) AS TICKETMONTH,
COUNT(DISTINCT TICKETID) AS DAILYTICKETCOUNT
FROM
NAT_JOBLINE
GROUP BY
YEAR(TICKETDATE),
MONTH(TICKETDATE)
ORDER BY
YEAR(TICKETDATE),
MONTH(TICKETDATE)
This does produce a count but it is wrong as it picks up the unique tickets for every day. I just want a unique count by month.
Try combining Year and Month into one field, and grouping on that new field.
You may have to cast them to varchar to ensure that they don't simply get added together. Or.. you could multiple through the year...
SELECT
(YEAR(TICKETDATE) * 100) + MONTH(TICKETDATE),
count(*) AS DAILYTICKETCOUNT
FROM NAT_JOBLINE GROUP BY
(YEAR(TICKETDATE) * 100) + MONTH(TICKETDATE)
Presuming that TICKETID is not a primary or unique key, but does appear multiple times in table NAT_JOBLINE, that query should work. If it is unique (does not occur in more than 1 row per value), you will need to select on a different column, one that uniquely identifies the "entity" that you want to count, if not each occurance/instance/reference of that entity.
(As ever, it is hard to tell without working with the actual data.)
I think you need to remove the first distinct. You already have the group by. If I was the first Distict I would be confused as to what I was supposed to do.
SELECT
YEAR(TICKETDATE) as TICKETYEAR,
MONTH(TICKETDATE) AS TICKETMONTH,
COUNT(DISTINCT TICKETID) AS DAILYTICKETCOUNT
FROM NAT_JOBLINE
GROUP BY YEAR(TICKETDATE), MONTH(TICKETDATE)
ORDER BY YEAR(TICKETDATE), MONTH(TICKETDATE)
From what I understand from your comments to Phillip Kelley's solution:
SELECT TICKETDATE, COUNT(*) AS DAILYTICKETCOUNT
FROM NAT_JOBLINE
GROUP BY TICKETDATE
should do the trick, but I suggest you update your question.
The following code returns a couple of numbers, identifying people who take part in more than three activities.
SELECT pnr
FROM Participates
GROUP BY pnr
HAVING count(activities)>3;
I want the answer to be the number of people who participate in more than three activities though, i.e. "4", instead of four unique numbers. What to do?
Access supports derived tables.
SELECT COUNT(*) AS NumberOfParticipants FROM
(
SELECT pnr
FROM Participates
GROUP BY pnr
HAVING count(activities)>3
) T
You will need a WHERE clause on the pnr field to uniquely identify one of your groupings:
SELECT COUNT(pnr)
FROM Participates
GROUP BY pnr
WHERE pnr = 'whatever'
HAVING COUNT(activities)>3
The order of my clauses might be wrong
Select Count(Distinct pnr)
From Participates
Having Count(activities) > 3