I have a table of inventory items (holds description, details of item etc.), a table of stock (physical items that we have - items of inventory), and a suppliers table (who supply the stock, but may differ from time to time).
Suppliers -- Stock -- Inventory
Inventory has many stock. Suppliers have many stock. Stock has one supplier, and one inventory
I'm trying to run a query to get all data from inventory, and count how many suppliers it has through a sub query. However, I need to use SELECT *
What I have at the moment:
SELECT
( SELECT COUNT(DISTINCT SupplierID)
FROM Stock
WHERE Stock.InventoryID = Inventory.ID
) AS Suppliers
, *
FROM `Inventory`;
I've tried variations on this, swapping the field order (seen this elsewhere on this site), changing the sub-query etc.
However, it tells me there's an error near '* FROM'. Can anyone suggest a way to do this query please?
Use table aliases:
SELECT (SELECT COUNT(DISTINCT s.SupplierID)
FROM Stock s
WHERE s.InventoryID = i.ID
) AS Suppliers, i.*
FROM `Inventory` i;
The need for a qualification on * is described in the documentation:
Use of an unqualified * with other items in the select list may
produce a parse error. To avoid this problem, use a qualified
tbl_name.* reference
SELECT AVG(score), t1.* FROM t1 ...
Related
Ok I've spent a week trying to figure this out but I can't seem to find what I'm looking for. There are two similar problems that, I think, are easier to explain after seeing the pseudo(ish) code. Here is the first one
SELECT P_CODE, P_DESCRIPT, #diff
FROM PRODUCT
WHERE #diff :=
(SELECT ROUND(ABS(P_PRICE -(SUM(P_PRICE)/COUNT(P_PRICE))),2)
FROM PRODUCT
WHERE P_PRICE in
(SELECT P_PRICE
FROM PRODUCT));
Basically, I have product table where I'm trying to return the primary key, description, and difference between the product's price and the average price for all entries. In a similar note here is the second problem
SELECT *, #val
FROM LINE
WHERE P_CODE in
(SELECT P_CODE
FROM LINE
HAVING COUNT(P_CODE) >
(#val = (SELECT COUNT(*) FROM LINE)/(SELECT COUNT(DISTINCT P_CODE)
FROM LINE)));
Here I'm trying to return all fields from the line table (which is basically a receipt table) for which the product for that entry has more items sold than the average number sold
Is it clear what I'm trying to do with these? I'm trying to return other values as well as a calculated value that I can only calculate using values from another table (in list form if that wasn't clear). I'm not too sure but perhaps JOIN statements might work here? I'm new to mysql and haven't quite understood how to best employ JOIN statements yet. If someone could show me how to approach problems like these or at least point me to a link that describes how to do this (as I've had no luck finding one)
Join with a subquery that returns the average price:
SELECT p.p_code, p.p_descript, ROUND(ABS(p.p_price - x.avg_price)) AS price_diff
FROM product AS p
CROSS JOIN (
SELECT AVG(p_price) AS avg_price
FROM product
) AS x
Notice that there's a built-in AVG() function, you don't need to use SUM() and COUNT(). Also, there's no point to WHERE p_price in (SELECT p_price FROM product) -- that test is obviously always true.
SELECT l.*
FROM line AS l
JOIN (
SELECT p_code, COUNT(*) AS code_count
FROM line
GROUP BY p_code
) AS l1 ON l.p_code = l1.p_code
JOIN (
SELECT COUNT(*)/COUNT(DISTINCT p_code) AS avg_count
FROM line
) AS x ON l1.code_count > x.avg_count
Basically, I have product table where I'm trying to return the primary key, description, and difference between the product's price and the average price for all entries
Using MySQL's user variables makes the queries a bit harder.
There are many methods to get what you need.
Method one
Using a inner select or a subquery
SELECT
PRODUCT.P_CODE
, PRODUCT.P_DESCRIPT
, ROUND(ABS((PRODUCT.P_PRICE) - (SELECT AVG(PRODUCT_INNER.P_PRICE) FROM PRODUCT AS PRODUCT_INNER)), 2) AS diff
FROM
PRODUCT
Method two
Using a CROSS JOIN
Query
SELECT
PRODUCT.P_CODE
, PRODUCT.P_DESCRIPT
, ROUND(ABS(PRODUCT.P_PRICE - product_avg.avg_product_price), 2) AS diff
FROM
PRODUCT
CROSS JOIN
(SELECT
AVG(PRODUCT.P_PRICE) AS avg_product_price
FROM
PRODUCT) AS product_avg
I have 2 tables, one containing tickets and the other routes. I want to produce 2 attributes, flight_DATE and route_CODE, for the greatest numbers of tickets sold. Since there is no attribute that stores the number of tickets sold I have to perform a query finding the max() on the number of count(ticket_ID), as each ticket_ID represents a ticket sold... right? I have no actual database to try this out so that's my query:
SELECT routes.ROUTE_CODE , tickets.FLIGHT_DATE
FROM routes JOIN tickets ON routes.ROUTE_CODE = tickets.ROUTE_CODE
WHERE count(ticket.TICKET_ID) = (
SELECT max(count(ticket.TICKET_ID)
)
I am not so confident with SQL so is this even correct??? thanks in advance!
The idea behind your query is correct, but you wrote the max calculation without a level, so you will get the count of all the tickets sold.
You also cannot put in your where clause a condition on an aggregated column (as you did with count(ticket.TICKET_ID); that kind of condition goes to the having clause.
This one should do what you need
SELECT ROUTE_CODE, FLIGHT_DATE
JOIN tickets
GROUP BY ROUTE_CODE , FLIGHT_DATE
HAVING count(tickets.TICKET_ID) = ( /*filter the row with count = max count */
SELECT max(CNT) /* get the max of the counts */
FROM (
SELECT count(TICKET_ID) as CNT /* get the counts at desired levels */
FROM tickets
GROUP BY FLIGHT_DATE, ROUTE_CODE
)
)
I removed the join with routes table because the only column you were using (ROUTE_CODE) is available on the tickets table too, but that may be useful if you want to select more data from that table and definitely was not an error.
BTW, if you don't have a database available for testing, you can try your queries on sites like rextester
Please see above for the data structure. I am trying to write an SQL query to get the average number of customers for each session
My attempt:
select avg(A.NumberCustomer)
from(
select SessionName, count(distinct customers.Idcustomer) as NumberCustomer,
from customers, enrollments, sessions
where customers.Idcustomer=enrollments.Idcustomer and enrollments.Idsession=sessions.Idsession
group by sessions.SessionName
) A
But I seem to get an error on the from customers, enrollments, sessions line
Not sure about this, any help appreciated.
Thanks
You have and extra comma that you should to delete:
select avg(A.NumberCustomer)
from(
select SessionName,
count(distinct customers.Idcustomer) as NumberCustomer, #<--- here
from customers, enrollments, sessions
where customers.Idcustomer=enrollments.Idcustomer
and enrollments.Idsession=sessions.Idsession
group by sessions.SessionName
) A
By the way, I suggest to you to move to SQL'99 join syntax for readability reasons:
SELECT
avg(A.NumberCustomer)
FROM (
select
SessionName,
count(distinct customers.Idcustomer) as NumberCustomer
from customers
inner join enrollments
on customers.Idcustomer=enrollments.Idcustomer
inner join sessions
on enrollments.Idsession=sessions.Idsession
group by sessions.SessionName
) A
Also, nice diagram on question and remember to include your error message next time.
For the average number of customers in each session, you should be able to use just the enrollments table. The average would be the number of enrollments divided by the number of sessions:
select count(*) / count(distinct idSession)
from enrollments e;
This makes the following assumptions:
All sessions have at least one customer (your original query had this assumption as well).
No customer signs up multiple times for the same session.
Let's say I have a query:
select product_id, price, price_day
from products
where price>10
and I want to join the result of this query with itself (if for example I want to get in the same row product's price and the price in previous day)
I can do this:
select * from
(
select product_id, price, price_day
from products
where price>10
) as r1
join
(
select product_id, price, price_day
from products
where price>10
) as r2
on r1.product_id=r2.product_id and r1.price_day=r2.price_day-1
but as you can see I am copying the original query, naming it a different name just to join its result with itself.
Another option is to create a temp table but then I have to remember to remove it.
Is there a more elegant way to join the result of a query with itself?
self join query will help
select a.product_ID,a.price
,a.price_day
,b.price as prevdayprice
,b.price_day as prevday
from Table1 a
inner join table1 b
on a.product_ID=b.product_ID and a.price_day = b.price_day+1
where a.price >10
You could do a bunch of things, just a few options could be:
Just let mysql handle the optimization
this will likely work fine until you hit many rows
Make a view for your base query and use that
could increase performance but mostly increases readability (if done right)
Use a table (non temporary) and insert your initial rows in there. (unfortunately you cannot refer to a temporary table more than once in a query)
this will likely be more expensive performance wise until a certain number of rows is reached.
Depending on how important performance is for your situation and how many rows you need to work with the "best" choice would change.
Just to get duplicates in the same row?
select product_id as id1, price as price1, price_day as priceday1, product_id as id2, price as price2, price_day as priceday2,
from products
where price>10
Pretty new to sql statements here so this one is a bit tricky for me.
I have two tables: sold and product. Sold(SID, UPC, Date) Product(UPC, Name, Brand)
I need to find in how many stores(sid) does one brand outsell another brand.
I was thinking it was something like:
select count(*) from sold natural join product
where count(brand = 'sony') > count(brand = 'samsung');
Clearly that isn't valid however...
SELECT COUNT(*)
FROM (
SELECT SID
FROM Sold
JOIN product
ON product.UPC = Sold.UPC -- otherwise we have a cartesian product
GROUP BY SID -- if we need totals _by store_, we need to group on that.
HAVING SUM(brand='sony') > SUM(brand='samsung')
) Totals.