I have the following, working MySQL query:
SELECT
a.id id,
a.price price,
a.stock stock,
a.max_per_user max_per_user,
a.purchased purchased,
b.quantity owned
FROM
shop_items a
JOIN shop_inventory b
ON b.iid=a.id
AND b.cid=a.cid
WHERE
a.cid=1
AND a.szbid=0
AND a.id IN(3,4)
The JOIN joins the table shop_inventory b to return b.quantity owned. However, if there is no record in the shop_inventory b table where b.iid=a.id I want it to return b.quantity = 0. How would I do this?
Use LEFT JOIN instead. And COALESCE since some of the records where null (I guess). Try,
SELECT a.id id,a.price price,a.stock stock,
a.max_per_user max_per_user,a.purchased purchased,
COALESCE(b.quantity, 0) owned
FROM shop_items a
LEFT JOIN shop_inventory b
ON b.iid=a.id AND b.cid=a.cid
WHERE a.cid=1 AND
a.szbid=0 AND
a.id IN(3,4)
Something like this should do the trick.
SELECT a.id id,a.price price,a.stock stock,
a.max_per_user max_per_user,a.purchased purchased,
COUNT(b.quantity) AS owned
FROM shop_items a
LEFT JOIN shop_inventory b
ON b.iid=a.id AND b.cid=a.cid
WHERE a.cid=1 AND a.szbid=0 AND a.id IN(3,4)
GROUP BY id
You want to use a LEFT JOIN instead of a JOIN.
SELECT a.id id,a.price price,a.stock stock,
a.max_per_user max_per_user,a.purchased purchased,
b.quantity owned
FROM shop_items a
LEFT JOIN shop_inventory b ON b.iid=a.id AND b.cid=a.cid
WHERE a.cid=1 AND a.szbid=0 AND a.id IN(3,4)
This will make fields in b NULL if they do not match the ON clause.
If you want it to be 0, you can use IFNULL
SELECT IFNULL(b.quantity, 0) owned
This would be where you use Left Join and Group By. If all you need is the count of items from b, that is.
SELECT a.id id,a.price price,a.stock stock,
a.max_per_user max_per_user,a.purchased purchased,
COUNT(b.quantity owned) as quantity_owned
FROM shop_items a
LEFT JOIN shop_inventory b
ON b.iid=a.id AND b.cid=a.cid
WHERE a.cid=1 AND a.szbid=0 AND a.id IN(3,4)
GROUP BY a.id
Related
This query gives an error if subquery return more than 1 row. I separated the queries and use mysqli_multi_query(), but both queries data is displayed in two tables.
So I decided to make the one query.
SELECT DISTINCT category ,
(SELECT COUNT(products.name)
FROM products
where category_id=categories.id
) AS total_products,
(
SELECT SUM(quantity) FROM productstock a
LEFT JOIN products b ON a.product_id=b.id
LEFT JOIN categories c ON b.category_id=c.id
where c.deleted=0
GROUP BY category_id
) AS available_stock,
SUM(product_qty*orignalCost) AS SaleWise_cost,
SUM(product_qty*saleprice) AS SaleWise_price,
SUM(product_qty*saleprice) AS total_sale ,
SUM((product_qty*saleprice)-(product_qty*orignalCost)) AS profit
FROM categories
INNER JOIN products ON categories.id = products.category_id
INNER JOIN sales ON sales.product_id = products.id
INNER JOIN productstock ON productstock.product_id = products.id
WHERE categories.deleted=0
GROUP BY category_id
As available stock is corelated subquery so joining condition must be added in where clause inside subquery. please check this pseudocode
(
SELECT SUM(quantity) FROM productstock a
LEFT JOIN products b ON a.product_id=b.id
LEFT JOIN categories c ON b.category_id=c.id
where c.deleted=0 AND b.category_id = categories.id
) AS available_stock
Another way
(SELECT SUM(quantity)
FROM products b
INNER JOIN productstock a
ON b.id = a.product_id
AND b.id = products.id
AND b.category_id = categories.id) AS available_stock
I have two tables: users and courses. Inside users table i have filed course where i have course id. Inside courses table i have just ID and NAME.
I need to get popular course. I do request:
SELECT u.course, COUNT(*) as freq FROM users u INNER JOIN courses c ON u.course = c.id GROUP BY u.course
As a result: id => freq. But i need to replace ID to NAME of course. How?
Thanks.
You don't say what database you use, but I would assume you can use CTEs since most modern databases do. Your query can be written as:
with x as (
select course, count(*) as freq from users group by course
),
y as (
select max(freq) as max_freq from x
)
select c.name, x.freq
from x
join y on x.freq = y.max_freq
join courses c on c.id = x.course
This query has the [desirable?] side effect that it shows more than one course, if there are more than one tied in first place.
Add c.name to both the SELECT clause and the GROUP BY clause.
SELECT u.course, c.name, COUNT(*) as freq
FROM users u
INNER JOIN courses c
ON u.course = c.id
GROUP BY u.course, c.name;
Demo: https://dbfiddle.uk/?rdbms=mariadb_10.3&fiddle=02a41e0f1e6407e516e91c49b4bdc1d2
SELECT u.course, COUNT(*) as freq, c.name FROM users u INNER JOIN courses c ON u.course = c.id GROUP BY u.course
If your DBMS supports row_number this will be suitable:
select t.id, c.name, t.cnt
from course c
join (
select c.id, count(1) cnt, ROW_NUMBER() over(order by count(1) desc) rn
from users u
join course c on c.id = u.course
group by id
)t on t.id = c.id and t.rn = 1
I have two tables called work and stuff both tables have same fields -
company, quality, quantity
I need the sum of all the quantity of work with group by company and quality and join the table with sum of all the quantity of stuff with group by company and quality
I didn't get the expected result.
SQLfiddel
http://sqlfiddle.com/#!9/eea577/6
working query
select st.company,st.quality,st.quantitys - ct.quantitys as balance from
(select company,quality,sum(quantity) as quantitys from stuff
group by quality,company) as st join (select company,quality,
sum(quantity) as quantitys from work group by quality,company)
as ct on `ct`.`company` = `st`.`company` and ct.quality = st.quality group by quality,company
u have missed the quality condition in the join
Try the following:
SELECT tableA.ID, tableA.`Year`, tableA.`Month`,
tableA.`Type`, tableA.instrument,
tableA.totalAmount, tableB.totalInstrument
FROM
(
SELECT a.ID, a.`Year`, a.`Month`,
b.`Type`, b.instrument,
SUM(b.`amount`) totalAmount
FROM `date` a
INNER JOIN `transactions` b
ON a.ID = b.id
GROUP BY b.`Type
) tableA
INNER JOIN
(
SELECT a.ID, a.`Year`, a.`Month`,
b.`Type`, b.instrument,
SUM(b.`instrument`) totalInstrument
FROM `date` a
INNER JOIN `transactions` b
ON a.ID = b.id
GROUP BY a.`Year`, a.`Month`
) tableB ON tableA.ID = tableB.ID AND
tableA.`Year` = tableB.`Year` AND
tableA.`Month` = tableB.`Month`
In a tutorial I saw this SQL query:
SELECT a.id as a_id, a.info as a_info,
b.id as b_id, b.info as b_info
FROM stats AS a
JOIN stats as b
ON a.id != b.id
LIMIT 25
The query is working well, but now I would need to add the WHERE condition. I have the table users. The table stats contains the column user_id.
I try to obtain all users from the table stats if users.city=1 (for example), but I still cannot to find a way, how to achieve that...
My problem is, that I currently have no clue, how to put into the query another JOIN (for table users).
I would be grateful for every advice, thank you
Well, as you use the table stats two times in your query, you would actually need two joins for the users table as well. (for stats A and stats B)
SELECT a.id as a_id, a.info as a_info,
b.id as b_id, b.info as b_info
FROM stats AS a
JOIN stats AS b ON a.id != b.id
JOIN users AS a_users ON a.user_id = a_users.id
JOIN users AS b_users ON b.user_id = b_users.id
WHERE a_users.city = 1
OR b_users.city = 1
LIMIT 25
So this is what you've got...
This is what you return
SELECT a.id as a_id, a.info as a_info, b.id as b_id, b.info as b_info
This is where it comes from
FROM stats AS a
JOIN stats as b on a.id != b.id
This is how many you want
LIMIT 25
So if you want to add the users table, add this after the other joins
JOIN users ON a.user_id = users.id
and to filter it, add this after the joins
WHERE users.city=1
Giving
SELECT a.id as a_id, a.info as a_info, b.id as b_id, b.info as b_info
FROM stats AS a
JOIN stats as b on a.id != b.id
JOIN users ON a.user_id = users.id
WHERE users.city=1
LIMIT 25
Here is one way to do that:
SELECT a.id as a_id, a.info as a_info,
b.id as b_id, b.info as b_info
FROM stats AS a
JOIN stats as b
ON a.id != b.id
where a.user_id in (select user_id from users where users.city = 1)
LIMIT 25
You can also express this as a join (which in MySQL is more efficient):
SELECT a.id as a_id, a.info as a_info,
b.id as b_id, b.info as b_info
FROM stats AS a
JOIN stats AS b
ON a.id != b.id
JOIN users AS u
ON a.user_id = u.user_id
AND u.city_id = 1
LIMIT 25
For convenience, I've reformatted your original SQL statement to make it readable by humans.
SELECT a.id AS a_id
, a.info AS a_info
, b.id AS b_id
, b.info AS b_info
FROM stats a
JOIN stats b
ON a.id != b.id
LIMIT 25
Your current query is almost returning a Cartesian product. Every row from stats is getting matched with every row from stats, except for matching itself. (Assuming that stats.id is a primary key or unique key.)
To add a join to the users table, to limit rows returned from a, for example:
SELECT a.id AS a_id
, a.info AS a_info
, b.id AS b_id
, b.info AS b_info
FROM stats a
JOIN users au ON au.id = a.user_id AND au.city=1
JOIN stats b ON a.id != b.id
LIMIT 25
If you want to limit rows returned for both a and b, add another join to the users table:
SELECT a.id AS a_id
, a.info AS a_info
, b.id AS b_id
, b.info AS b_info
FROM stats a
JOIN users au ON au.id = a.user_id AND au.city=1
JOIN stats b ON a.id != b.id
JOIN users bu ON bu.id = b.user_id AND bu.city=1
LIMIT 25
This is not the only way to accomplish this. For example, you could use an a.user_id IN (subquery) or an EXISTS (subquery) predicate.
(SQL is much easier to work with if you have it formatted in a way that is readable.)
I have 3 tables:
shops, PRIMARY KEY cid,zbid
shop_items, PRIMARY KEY id
shop_inventory, PRIMARY KEY id
shops a is related to shop_items b by the following: a.cid=b.cid AND a.zbid=b.szbid
shops is not directly related to shop_inventory
shop_items b is related to shop_inventory c by the following: b.cid=c.cid AND b.id=c.iid
Now, I would like to run a query which returns a.* (all columns from shops). That would be:
SELECT a.* FROM shops a WHERE a.cid=1 AND a.zbid!=0
Note that the WHERE clause is necessary.
Next, I want to return the number of items in each shop:
SELECT
a.*,
COUNT(b.id) items
FROM shops a
LEFT JOIN shop_items b ON b.cid=a.cid AND b.szbid=a.zbid
WHERE a.cid=1
GROUP BY b.szbid,b.cid
As you can see, I have added a GROUP BY clause for this to work.
Next, I want to return the average price of each item in the shop. This isn't too hard:
SELECT
a.*,
COUNT(b.id) items,
AVG(COALESCE(b.price,0)) average_price
FROM shops a
LEFT JOIN shop_items b ON b.cid=a.cid AND b.szbid=a.zbid
WHERE a.cid=1
GROUP BY b.szbid,b.cid
My next criteria is where it gets complicated. I also want to return the unique buyers for each shop. This can be done by querying shop_inventory c, getting the COUNT(DISTINCT c.zbid). Now remember how these tables are related; this should only be done for the rows in c which relate to an item in b which is owned by the respective shop, a.
I tried doing the following:
SELECT
a.*,
COUNT(b.id) items,
AVG(COALESCE(b.price,0)) average_price,
COUNT(DISTINCT c.zbid)
FROM shops a
LEFT JOIN shop_items b ON b.cid=a.cid AND b.szbid=a.zbid
LEFT JOIN shop_inventory c ON c.cid=b.cid AND c.iid=b.id
WHERE a.cid=1
GROUP BY b.szbid,b.cid
However, this did not work as it messed up the items value. What is the proper way to achieve this result?
I also want to be able to return the total number of purchases made in each shop. This would be done by looking at shop_inventory c and adding up the c.quantity value for each shop. How would I add that in as well?
Try this solution:
SELECT a.*,
COALESCE(b.item_cnt, 0) AS item_cnt,
COALESCE(b.avg_price, 0) AS avg_price,
COALESCE(b.buyer_cnt, 0) AS buyer_cnt
FROM shops a
LEFT JOIN (
SELECT a.cid,
a.szbid,
COUNT(*) AS item_cnt,
AVG(a.price) AS avg_price,
b.buyer_cnt
FROM shop_items a
LEFT JOIN (
SELECT cid,
iid,
COUNT(DISTINCT zbid) AS buyer_cnt
FROM shop_inventory
WHERE cid = 1
GROUP BY cid,
iid
) b ON a.cid = b.cid AND a.id = b.iid
WHERE a.cid = 1 AND
a.szbid <> 0
GROUP BY a.cid,
a.szbid
) b ON a.cid = b.cid AND a.zbid = b.szbid
WHERE a.cid = 1 AND
a.zbid <> 0
Instead of COUNT(DISTINCT c.zbid) + LEFT JOIN shop_inventory you could write a subselect:
SELECT
a.*,
COUNT(b.id) items,
AVG(COALESCE(b.price,0)) average_price,
( SELECT COUNT(DISTINCT c.zbid)
FROM shop_inventory c
WHERE c.cid=b.cid AND c.iid=b.id
)
FROM shops a
LEFT JOIN shop_items b ON b.cid=a.cid AND b.szbid=a.zbid
WHERE a.cid=1
GROUP BY b.szbid,b.cid