so I'm trying to compute the total cost per location by multiplying the sum of each item used with their respective price, this code is working for now :
create view location_costs as
select
City as location,
participant_item.SederStaple as item,
sum(ItemAmount) as quantity,
item.ItemPrice*sum(ItemAmount) as price
from participant_item
inner join item
on participant_item.SederStaple=item.SederStaple
group by item, location
order by location;
but I need to compute the sum of all of the total prices by location, so I'm adding the sum statement to my code :
create view location_costs as
select
City as location,
participant_item.SederStaple as item,
sum(ItemAmount) as quant,
sum(item.ItemPrice*sum(ItemAmount)) as price
from participant_item
inner join item
on participant_item.SederStaple=item.SederStaple
group by item, location
order by location;
and it's not working anymore:
error code 1111, invalid use of group function sql
I think you want the multipication before the sum():
select City as location, pi.SederStaple as item,
sum(ItemAmount) as quantity,
sum(ItemAmount * i.ItemPrice) as price
from participant_item pi inner join
item i
on pi.SederStaple = i.SederStaple
group by item, location
order by location;
Note that I introduced table aliases and used them for the columns that you qualified. You should qualify all column references in a query that references multiple tables.
Don't put the sum inside the sum:
select
pi.City as location,
pi.SederStaple as item,
sum(pi.ItemAmount) as quant,
sum(i.ItemPrice * pi.ItemAmount) as price
from
participant_item pi
inner join item i on pi.SederStaple = i.SederStaple
group by pi.City, pi.SederStaple
order by location;
In tidying up your aliasing I've guessed at which table these things came out of (i figured an item wouldn't have a city or a quantity, but a participant would) - you might need to tweak things a bit. Always fully alias your queries. It stops them mysteriously failing if in the future someone adds another column to a table with the same name
Also, while MySQL is quite happy to use aliases (location, item) in its group by, other databases aren't; keep the original names for your group by to make sure when your next job uses SQL Server you aren't caught out by this mysql-only "feature"
Related
the title doesnt describe it that well, my problem:
I have 2 tables, one table for orders, the other for the product.
An order can have n products associated with it.
I want to select those orders, where all their associated products have a status (attribute of the product) greater or equal to x. (So I know that every product of my order is "ready" and the order can be processed further)
Every ordered product has an OrderID
Any tips?
e: Just started with SQL, dont bash me if this is a stupid question
It's a matter of mindset.
You have to find the 'dual' form of your question ( -> double negation).
You need to find all the orders that have AT LEAST one line that is not ready.
Assuming your tables are the common:
Order(ID,bla,bla,bla) and Order Line(orderID, row#, status, bla, bla) FK orderid references order.
You can use this stub:
Select *
from orders O
where not exists ( select * from order_line OL
where ol.orderID=O.orderID --binding with outer query
and status <> 'ready'
)
SIDE NOTE: my query will produce also empty orders, to filter them just add to outer query and exists (select * from orderline oe where oe.orderid=o.orderid)
Here is a database schema:
customers (custID, firstname, familyname, town, state)
orders (orderID, custlD, date)
lineitems (orderID, itemlD, quantity, despatched)
items (itemID, description, unitcost, stocklevel)
itemSupplier (supplierID, itemlD)
supplier (supplierID, sName, sAddress, telephoneNo, delivers)
Here is the question:
If we assume that the description field in the items table uses a set of pre-defined categories (e.g., tents, spades, etc), then we can answer questions like, 'how many different kinds of tent does the shop sell?' Write a SQL query to list all items for which more than one of the same kind of item is sold and to find how many different types of that item are sold (i.e., a list with colunm headings: description; 'how many types are sold').
I tried to use DISTINCT in COUNT() function like this:
SELECT description, count(DISTINCT itemID) AS how_many_types_are_sold
FROM items
GROUP BY description
I'm not sure whether it's a right use of the functions or not. Is there any advice to solve this question? Thanks in advance:D
This query:
SELECT description, count(DISTINCT itemID) AS how_many_types_are_sold
FROM items
GROUP BY description;
Based on your description, this does what you want to do. But . . . you should be using DISTINCT only when necessary.
There is a really good chance that a column called itemID in a table called items is actually the primary key for the table. If so, then each row has a distinct value, and the COUNT(DISTINCT) is redundant. Based on this assumption, you can just count the number of rows that match:
SELECT description, count(*) AS how_many_types_are_sold
FROM items
GROUP BY description;
This is much preferred (because count(*) performs better than count(distinct)), assuming that itemID is unique in the table.
From my understanding, you do not need distinct in your select statement, as the group by will group every item based description which means,
SELECT description, count(*) AS how_many_types_are_sold FROM items GROUP BY description
but you can use above statement if only and if all the categories are predefined as you mentioned in your question, otherwise some not defined descriptions will be expected, in this case you need some kind of mapping table to map all the descriptions with all categories you have.
I've got a table with 11 columns and I want to create a query that removes the rows with duplicate names in the Full Name's column but keeps the row with the lowest value in the Result's column. Currently I have this.
SELECT
MIN(sql363686.Results2014.Result),
sql363686.Results2014.Temp,
sql363686.Results2014.Full Name,
sql363686.Results2014.Province,
sql363686.Results2014.BirthDate,
sql363686.Results2014.Position,
sql363686.Results2014.Location,
sql363686.Results2014.Date
FROM
sql363686.Results2014
WHERE
sql363686.Results2014.Event = '50m Freestyle'
AND sql363686.Results2014.Gender = 'M'
AND sql363686.Results2014.Agegroup = 'Junior'
GROUP BY
sql363686.Results2014.Full Name
ORDER BY
sql363686.Results2014.Result ASC ;
At first glance it seems to work fine and I get all the correct values, but I seem to be getting a different (wrong) value in the Position column then what I have in my database table. All other values seem to be right. Any ideas on what I'm doing wrong?
I'm currently using dbVisualizer connected to a mysql database. Also, my knowledge and experience with sql is the bare mimimum
Use group by and a join:
select r.*
from sql363686.Results2014 r
(select fullname, min(result) as minresult
from sql363686.Results2014 r
group by fullname
) rr
on rr.fullname = r.fullname and rr.minresult = r.minresult;
You have fallen into the trap of the nonstandard MySQL extension to GROUP BY.
(I'm not going to work with all those fully qualified column names; it's unnecessary and verbose.)
I think you're looking for each swimmer's best time in a particular event, and you're trying to pull that from a so-called denormalized table. It looks like your table has these columns.
Result
Temp
FullName
Province
BirthDate
Position
Location
Date
Event
Gender
Agegroup
So, the first step is to locate the best time in each event for each swimmer. To do this we need to make a couple of assumptions.
A person is uniquely identified by FullName, BirthDate, and Gender.
An event is uniquely identified by Event, Gender, Agegroup.
This subquery will get the best time for each swimmer in each event.
SELECT MIN(Result) BestResult,
FullName,BirthDate, Gender,
Event, Agegroup
FROM Results2014
GROUP BY FullName,BirthDate, Gender, Event, Agegroup
This gets you a virtual table with each person's fastest result in each event (using the definitions of person and event mentioned earlier).
Now the challenge is to go find out the circumstances of each person's best time. Those circumstances include Temp, Province, Position, Location, Date. We'll do that with a JOIN between the original table and our virtual table, like this
SELECT resu.Event,
resu.Gender,
resu.Agegroup,
resu.Result,
resu.Temp.
resu.FullName,
resu.Province,
resu.BirthDate,
resu.Position,
resu.Location,
resu.Date
FROM Results2014 resu
JOIN (
SELECT MIN(Result) BestResult,
FullName,BirthDate, Gender,
Event, Agegroup
FROM Results2014
GROUP BY FullName,BirthDate, Gender, Event, Agegroup
) best
ON resu.Result = best.BestResult
AND resu.FullName = best.FullName
AND resu.BirthDate = best.BirthDate
AND resu.Gender = best.Gender
AND resu.Event = best.Event
AND resu.Agegroup = best.Agegroup
ORDER BY resu.Agegroup, resu.Gender, resu.Event, resu.FullName, resu.BirthDate
Do you see how this works? You need an aggregate query that pulls the best times. Then you need to use the column values in that aggregate query in the ON clause to go get the details of the best times from the detail table.
If you want to report on just one event you can include an appropriate WHERE clause right before ORDER BY as follows.
WHERE resu.Event = '50m Freestyle'
AND resu.Gender = 'M'
AND resu.Agegroup = 'Junior'
I am fairly new to Databases and I am just beginning to understand the DML/queries, I have two tables, one named customer this contain customer data and one named requested_games, this contains games requested by the customers, I would like to write a query that will return the customers that have requested more than two games, so far when I run the query, I don't get the desired result, not sure if I'm doing it right.
Can anyone assist with this thanks,
Below is a snippet of the query
select customers.customer_name, wants_list.requested_game, wants_list.wantslists_id,count(wants_list.customers_ID)
from customers, wants_list
where customers.customers_ID = wants_list.customers_id
and wants_list.wantslists_id = wants_list.wantslists_id
and wants_list.requested_game > '2';
just include a HAVING clause
GROUP BY customers_ID
HAVING COUNT(*) > 2
depending on how you have your data setup you may need to do
HAVING COUNT(wants_list.requested_game) > 2
This is how I like to describe how a query works maybe itll help you visualize how the query executes :)
SELECT is making an order at a restaurant....
FROM is the menu you want to order from....
JOIN is what sections of the menu you want to include
WHERE is any customization you want to make to your order (aka no mushrooms)....
GROUP BY (and anything after) is after the order has been completed and is at your table...
GROUP BY tells your server to bring your types of food together in groups
ORDER BY is saying what dishes you want first (aka i want my entree then dessert then appetizer ).
HAVING can be used to pick out any mushrooms that were accidentally left on the plate....
etc..
I would like to write a query that will return the customers that
have requested more than two games
For this to happen you need to do the following
First you need to use GROUP BY to group the games based on customers (customers_id)
Then you need to use HAVING clause to get customers who requested more than two games
Then make this a SUBQUERY if you need more information on the customer like name
Finally you use a JOIN between customers and the sub query (temp) to display more information on the customer
Like the following query
SELECT customers.customer_id, customers.customer_name, game_count
FROM (SELECT customer_id, count(wantslists_id) AS game_count
FROM wants_list
GROUP BY customer_id
HAVING count(requested_game) > '2') temp
JOIN customers ON customers.customer_id = temp.customer_id
My actual tables are much more complex but here is a simplified example of the problem I am trying to work out.
Table contact: ContactID, ContactName, Pending
Table purchase: PurchaseID, ContactID, Amount, Pending, Date
Table contact_purchase_link: ContactID, PurchaseID (although it may seem like the link table is not necessary in this simplified example it is necessary in the large table schema)
Here is the query that I currently have:
SELECT DISTINCT contact.ContactID,
( SELECT SUM(Amount)
FROM purchase
WHERE purchase.ContactID = contact.ContactID
AND purchase.Pending = 0
) totalpurchase
FROM contact
INNER JOIN ( contact_purchase_link JOIN purchase
ON (contact_purchase_link.PurchaseID = purchase.PurchaseID
))
USING (ContactID)
WHERE purchase.Date > '2013-12-06' AND
AND contact.Pending =0
The problem is that I want the totalpurchase (the sum of the amount field) to be limited to the search criteria of the purchase table - meaning the query should only return the sum of the purchases after the specified date per contact. I think in order to use a group by clause the query would have to be based off the purchase table but I need the query to use the contact table so that all contacts are listed with their total purchase amounts and other relevant client data.
Is there any way to do this within one query?
To further clarify:
This query is being generated as part of a search engine. An example of why a query like this would be done is if a user wanted to generate a contact list of lastnames starting with A with purchases of a specific item or as in this example of purchases for a specific date. So that in general the query would have to generate a list of all contacts and their data (with possible search criteria on the type of contact such as all lastnames starting with 'A' etc.) and the query can also include search criteria on the purchase table such as the date of the purchase and whether the purchase was for specific items etc.
I am trying to add in the option to also list the sum of the purchases for the contact however that sum has to be limited to the search criteria for the purchase table as well and not the sum of all the contacts purchases.
If I understand your question correctly, you need to move the date comparison inside the first subquery:
SELECT DISTINCT contact.ContactID,
( SELECT SUM(Amount)
FROM purchase
WHERE purchase.ContactID = contact.ContactID
AND purchase.Pending = 0
AND purchase.Date > '2013-12-06'
) totalpurchase
FROM contact
INNER JOIN ( contact_purchase_link JOIN purchase
ON (contact_purchase_link.PurchaseID = purchase.PurchaseID
)
USING (ContactID)
WHERE purchase.Date > '2013-12-06'
AND contact.Pending =0
But the comments are right - I corrected a couple of what appears to be syntax errors, and I'm not sure about the join to contact_purchase_link. Improve your question and my answer will be less like guesswork.