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`
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 build a query a month ago on a website. It was working fine. But after a month I was informed that the website become very slow to load the page.
When I search for the problem, I found that my query is executing very slow to fetch the data from mysql database. Then I check for the database and found that the 4 tables which I was using by joins, have around 216850, 167634, 64000, 931 rows respectively.
I have already have indexed that tables. So, where I'm lacking. Please help guys.
[Edit]
Table1: user_alert
Records: 216850
DB Type: InnoDB
Indexes: id(primary)
Table2: orders
Records: 167634
DB Type: InnoDB
Indexes: id(primary), order_id, customer_id
Table3: user_registration
Records: 64000 around
DB Type: InnoDB
Indexes: id(primary), email_address
Table4: cities
Records: 931
DB Type: InnoDB
Indexes: id(primary)
Query:
SELECT uas.alert_id, uas.user_id, uas.status, ur.first_name, ur.last_name, ur.email_address, o.order_id,
CASE WHEN ct.city_name IS NULL THEN uas.city_name ELSE ct.city_name END AS city_name
FROM `user_alert` uas
LEFT JOIN orders o ON o.customer_id = uas.user_id
LEFT JOIN user_registration ur ON ur.id = uas.user_id
LEFT JOIN `cities` ct ON ct.city_id = uas.city_id
WHERE uas.status = '1'
GROUP BY uas.user_id
ORDER BY uas.create_date DESC
GROUP BY is used to aggregate values up. For example if you wanted the count of orders by a user you could use COUNT(o.order_id).....GROUP BY uas.user_id. There are multiple orders for each user, but the aggregate function is just counting them here. However if you just select o.order_id when you have a GROUP BY uas.user_id it doesn't know which of the possibly many order_id values to return for that user id.
In this case it possibly doesn't matter as it looks like the order table is the only one where there is multiple rows per use. If you want the latest one you could just use MAX(o.order_id) (assuming that the order_id is assigned is order). But if you wanted the order value it becomes more difficult.
SELECT uas.alert_id, uas.user_id, uas.status, ur.first_name, ur.last_name, ur.email_address, MAX(o.order_id) AS LatestOrderId,
IFNULL(ct.city_name, uas.city_name) AS city_name
FROM `user_alert` uas
LEFT JOIN orders o ON o.customer_id = uas.user_id
LEFT JOIN user_registration ur ON ur.id = uas.user_id
LEFT JOIN `cities` ct ON ct.city_id = uas.city_id
WHERE uas.status = '1'
GROUP BY uas.user_id
ORDER BY uas.create_date DESC
If you wanted the (say) value of the latest order then it becomes more difficult.
SELECT uas.alert_id, uas.user_id, uas.status, ur.first_name, ur.last_name, ur.email_address, Sub1.MaxOrderId AS LatestOrderId, o.order_value
IFNULL(ct.city_name, uas.city_name) AS city_name
FROM `user_alert` uas
LEFT JOIN (SELECT customer_id, MAX(order_id) AS MaxOrderId FROM orders GROUP BY customer_id) Sub1 ON Sub1.customer_id = uas.user_id
LEFT OUTER JOIN orders o ON o.customer_id = Sub1.user_id AND o.order_id = Sub1.MaxOrderId
LEFT JOIN user_registration ur ON ur.id = uas.user_id
LEFT JOIN `cities` ct ON ct.city_id = uas.city_id
WHERE uas.status = '1'
ORDER BY uas.create_date DESC
Or doing a bit of a fiddle based on GROUP_CONCAT
SELECT uas.alert_id, uas.user_id, uas.status, ur.first_name, ur.last_name, ur.email_address,
SUBSTRING_INDEX(GROUP_CONCAT(o.order_id ORDER BY o.order_id DESC), ',', 1) AS LatestOrderId,
SUBSTRING_INDEX(GROUP_CONCAT(o.order_value ORDER BY o.order_id DESC), ',', 1) AS LatestOrderValue,
IFNULL(ct.city_name, uas.city_name) AS city_name
FROM `user_alert` uas
LEFT OUTER JOIN orders o ON o.customer_id = uas.user_id AND o.order_id = Sub1.MaxOrderId
LEFT JOIN user_registration ur ON ur.id = uas.user_id
LEFT JOIN `cities` ct ON ct.city_id = uas.city_id
WHERE uas.status = '1'
GROUP BY uas.user_id
ORDER BY uas.create_date DESC
I have two tables namely locations and pilots. I have been trying to fetch data based on location_id i.e selecting pilots who are flying in a particular location_id order by date(date of schedule).
I am using group by as i need only distinct pilots to be displayed.
select B.*,
A.rather_to_be_flying_now,
A.here_now,
A.flying,
A.when,
A.my_favorite,
A.start,
A.end,
A.Locationid
from locations A
inner join pilots B
on A.Pilotid=B.pilot_id
where A.VenueID='$venueid'
and (A.flying='1' or A.here_now='1')
group by A.Pilotid
ORDER BY A.start
The query works good if i wont include a group by clause. It returns the following result
with out group by clause
with group by clause
But the above table shows wrong order, as the output must return start time as 2013-01-24 02:00:00 for pilotid 1 (Chronological order).
You can use MIN()
select B.*,
A.rather_to_be_flying_now,
A.here_now,
A.flying,
A.when,
A.my_favorite,
MIN(A.start) as start,
A.end,
A.Locationid
from locations A
inner join pilots B
on A.Pilotid=B.pilot_id
where A.VenueID='$venueid'
and (A.flying='1' or A.here_now='1')
group by A.Pilotid
ORDER BY A.start
Try this instead:
SELECT
B.*,
A.rather_to_be_flying_now,
A.here_now,
A.flying,
A.when,
A.my_favorite,
A.start,
A.end,
A.Locationid
FROM locations A
INNER JOIN
(
SELECT pilotid, MIN(start) MinStart
FROM locations
GROUP BY pilotid
) a2 ON A.pilotId = a2.pilotId
AND a.start = a2.minStart
INNER JOIN pilots B on A.Pilotid = B.pilot_id
WHERE A.VenueID = '$venueid'
AND (A.flying='1' OR A.here_now='1');
ORDER BY A.start ;
This will give you only those pilots with the minimum start date.
Try this query -
SELECT
p.pilit_id, l.location_id, l.start
FROM pilots p
JOIN (SELECT l1.*
FROM locations l1
JOIN (SELECT location_id, MIN(start) start
FROM locations
GROUP BY locations) l2
ON l1.id = l2.id AND l1.start = l2.start
) l
ON l.pilot_id = p.pilot_id
GROUP BY p.pilot_id
Add your WHERE condition.
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