How to select counts from different tables with foreign keys? - mysql

city
----------------------
id city_name
1 Pune
2 Mumbai
3 Banglore
Branches
----------------------
id branch_name city_id
1 Magarpatta 1
2 Wagholi 1
3 Kurla 2
4 CST 2
5 Thane 2
6 Anekal 3
Employees
----------------------
id employee_name city_id
1 Arun 1
2 Varun 1
3 Mahesh 2
4 Umesh 2
5 Prakash 1
6 Kedar 3
Expected result
-----------------------------
id(city) city_name No_of_Branch no_of_employee
1 Pune 2 3
2 Mumbai 3 2
3 Banglore 1 1
Can I get above result in single Query?
Can I Use Crosstab in this scenario? How?

SELECT c.*, count(DISTINCT b.id) AS No_of_Branch, count(DISTINCT e.id) AS no_of_employee
FROM city c
LEFT JOIN branches b ON (b.city_id=c.id)
LEFT JOIN employees e ON (e.city_id=c.id)
GROUP BY c.id
Or
SELECT c.*,
(SELECT count(b.id) FROM branches b WHERE b.city_id=c.id) AS No_of_Branch,
(SELECT count(e.id) FROM employees e WHERE e.city_id=c.id) AS no_of_employee
FROM city c

Try this:
SELECT c.id, c.city_name,
COUNT(b.id) AS No_of_Branch,
no_of_employee
FROM city c
LEFT JOIN branches b ON b.city_id = c.id
LEFT JOIN (
SELECT city_id, COUNT(e.id) AS no_of_employee
FROM employees AS e
GROUP BY e.city_id
) AS e_grp ON e_grp.city_id = c.id
GROUP BY c.id, c.city_name
The trick here is to use a derived table containing the count of employees per city_id. I you just join all tables together you will end up with duplicate counts of employees.
Demo here

Related

mysql query not working as expected complex

I have 3 tables in which all 3 tables are joined to get the result.
Below is the table,
//tbl_order
order_id order_no_first order_no order_no_last order_date
---------------------------------------------------------------------
1 C 1000 a 2017-05-16
2 C 1001 a 2017-05-16
3 C 1001 b 2017-05-16
4 A 1002 a 2017-05-16
5 A 1002 b 2017-05-16
//tbl_assign
assign_id order_id order_no_first central_status central_assign_unit
----------------------------------------------------------------------------
1 1 C 1 1
2 2 C 1 1
3 3 C 1 1
4 4 A 1 1
//tbl_unit_status
status_id assign_id status_status
---------------------------------------
1 1 Cutter
2 1 Stitch
3 1 Delivery
4 2 Cutter
5 2 Stitch
6 3 Cutter
7 4 Cutter
I want the result as below,
//Required output
order_id assign_id order_no_first order_no order_no_last status_status
---------------------------------------------------------------------------
2 2 C 1001 a Stitch
3 3 C 1001 b Cutter
4 4 A 1002 a Cutter
5 A 1002 b
from the table tbl_unit_status the status below status_status field, if it is Despatch then do not display that result.
I have tried to get the above result. But no success below is my code.
`SELECT *
FROM tbl_order o
LEFT JOIN tbl_assign a
ON a.order_id = o.order_id AND o.order_no_first = a.order_no_first
LEFT JOIN (
SELECT u.assign_id, max(u.status_id) AS maxid
FROM tbl_unit_status u GROUP BY u.assign_id) uu
ON uu.assign_id = a.assign_id
LEFT JOIN tbl_unit_status u2 on u2.status_id = uu.maxid
WHERE a.central_status = 1 AND a.central_assign_unit = 1
OR (u2.status_status != "Delivery" AND u2.status_status != "Despatch")
GROUP BY o.order_id
From the above code, the result is
//wrong output
order_id assign_id order_no_first order_no order_no_last status_status
---------------------------------------------------------------------------
1 1 C 1000 a Delivery
2 2 C 1001 a Stitch
3 3 C 1001 b Cutter
4 4 A 1002 a Cutter
5 A 1002 b
Is there any way to get the Required output as soon in the first output. I have tried and am stuck in here.
Thank you.
Use parenthesis correctly arround AND OR clauses and I recommend using NOT LIKE instead of != when dealing with strings.
SELECT *
FROM tbl_order o
LEFT JOIN tbl_assign a
ON a.order_id = o.order_id AND o.order_no_first = a.order_no_first
LEFT JOIN (
SELECT u.assign_id, max(u.status_id) AS maxid
FROM tbl_unit_status u GROUP BY u.assign_id) uu
ON uu.assign_id = a.assign_id
LEFT JOIN tbl_unit_status u2 on u2.status_id = uu.maxid
WHERE a.central_status = 1 AND (a.central_assign_unit = 1 OR u2.status_status NOT LIKE 'Delivery' AND u2.status_status NOT LIKE 'Despatch')
GROUP BY o.order_id
Obs: I can't comment due to my reputation, I'm sorry
You should be using AND instead of OR in your where clause. You don't need the parentheses either.
SELECT *
FROM tbl_order o
LEFT JOIN tbl_assign a
ON a.order_id = o.order_id
AND o.order_no_first = a.order_no_first
LEFT JOIN
(SELECT u.assign_id, max(u.status_id) AS maxid
FROM tbl_unit_status u
GROUP BY u.assign_id
) uu ON uu.assign_id = a.assign_id
LEFT JOIN tbl_unit_status u2
on u2.status_id = uu.maxid
WHERE a.central_status = 1
AND a.central_assign_unit = 1
AND (
u2.status_status IS NULL
OR
u2.status_status NOT IN ("Delivery", "Despatch")
)
GROUP BY o.order_id

MYSQL Stuck Generating temp table (massive query)

I have 4 tables (1 to many):
Dont say anything about that "email" relation. It is how my developer boss built it years ago.
EMPLOYEES (+-50 results)
------------------------------------------------
id name
1 EmpName 1
2 EmpName 2
CUSTOMERS (+50k results)
------------------------------------------------
id name email employee_assigned
1 John john#doe.com 12
2 Donald donald#duck.com 6
INTERESTS_CATEGORIES (+650k results)
------------------------------------------------
id customer_email category_id
1 john#doe.com 97
2 john#doe.com 13
3 donald#duck.com 56
4 donald#duck.com 126
5 donald#duck.com 45
INTERESTS_PRODUCTS (+650k results)
------------------------------------------------
id customer_email product_id
1 john#doe.com 78
2 john#doe.com 23
3 donald#duck.com 19
4 donald#duck.com 56
5 donald#duck.com 45
So I need to filter the customers by their assigned employee and their interests.
And here is the query:
SELECT
*
FROM
(
SELECT
customers.id AS 'id',
customers.name AS 'first_name',
customers.email,
employees.id AS 'employee_id'
FROM
customers,
employees
WHERE
employees.id = 2
AND
customers.employee_assigned = employees.id
) AS myCustomers
LEFT JOIN interests_categories
ON interests_categories.customer_email = myCustomers.email
LEFT JOIN interests_products
ON interests_categories.customer_email = myCustomers.email
WHERE
(
interests_categories.category_id = 20
OR
interests_categories.category_id = 21
)
GROUP BY myCustomers.email
So, the problem:
If the employee has a low number of assigned customers (like 3) query
is successfull.
If the employee has a medium-high number of assigned customers (over 100) query stucks.
I execute SHOW PROCESSLIST and it is stucked "Generating temp table".
Anyone has idea? :(
Thank you.
Check the indexes on your tables and try this:
SELECT
c.id AS 'id',
c.name AS 'first_name',
c.email,
e.id AS 'employee_id'
ic.*,
ip.*
FROM customers c
JOIN employees e
ON c.employee_assigned = e.id
LEFT JOIN interests_categories ic
ON ic.customer_email = c.email
LEFT JOIN interests_products ip
ON ic.customer_email = c.email
WHERE
(
ic.category_id IN (20,21)
AND e.id = 2
)
GROUP BY myCustomers.email
Incidentally, a less dumb design might look like as follows. If it was me, I'd start with this, and provide properly representative CREATE and INSERT statements accordingly. Also, I'm curious about where category_id comes from - because that's potentially an area for further optimization.
EMPLOYEES
------------------------------------------------
employee_id name
6 EmpName 1
12 EmpName 2
CUSTOMERS
------------------------------------------------
customer_id name email employee_assigned
1 John john#doe.com 12
2 Donald donald#duck.com 6
INTERESTS_CATEGORIES
------------------------------------------------
customer_id category_id
1 97
1 13
2 56
2 126
2 45
INTERESTS_PRODUCTS
------------------------------------------------
customer_id product_id
1 78
1 23
2 19
2 56
2 45

mysql complicated inner join on many to many

I have 7 tables db_category, db_city, db_locality, db_shop, db_shop_locality, db_shop_recommended, db_shop_views.
db_category
category_id category_name publish
1 Apparel 1
db_city
city_id city_name publish
1 bangalore 1
db_locality
locality_id locality_name publish
1 kalyan nagar 1
2 Madiwala 1
db_shop
shop_id category_id city_id locality_id shop_name publish
1 1 1 1 name 1
2 1 1 2 name1 1
3 1 1 1 name2 1
4 1 1 1 name3 1
db_shop_recommended
recommended_id category_id shop_id priority publish
1 1 1 1 1
2 1 2 2 1
db_shop_views
views_id shop_id ip_addr publish
1 1 127.0.0.1 1
2 2 ::1 1
3 4 127.0.0.1 1
4 4 ::1 1
5 3 ::1 1
I want to join all the above tables. And the conditions for the join are,
display all the rows from db_shop when publish=1 and join db_category, db_city and db_locality with db_shop
in db_shop_recommended who's priority=1 comes first and so on.
and shop_id not in db_shop_recommended, count shop_id not in db_shop_recommended from db_shop_views who's shop_id got more views.
My result should looks like below,
shop_id category_name city_name locality_name shop_name
1 Apparel bangalore kalyan nagar name (result based on `db_shop_recommended` who's priority is more)
2 Apparel bangalore Madiwala name1 (result based on `db_shop_recommended` who's priority is more)
4 Apparel bangalore kalyan nagar name4 (result based on `db_shop_views` who's view count is more)
3 Apparel bangalore kalyan nagar name3 (result based on `db_shop_views`)
I have no idea how to join and count the views. Is it possible to join in above method.
After lots of searching. Finally i got the answer.
SELECT DISTINCT s.shop_id, c.city_name, l.locality_name, ca.category_name, s.shop_name, s.shop_logo, s.cart_url, s.shop_about FROM db_shop s INNER JOIN db_city c ON c.city_id = s.city_id INNER JOIN db_category ca ON ca.category_id = s.category_id INNER JOIN db_locality l ON l.locality_id = s.locality_id LEFT JOIN (SELECT * FROM db_shop_recommended r ORDER BY r.priority ASC) r1 ON s.shop_id = r1.shop_id LEFT JOIN (select distinct g.shop_id, g.cnt from (select distinct shop_id, count(shop_id) cnt from db_shop_views group by shop_id) g inner join (select max(s.cnt) max_cnt from(select distinct shop_id, count(shop_id) cnt from db_shop_views group by shop_id) s) m on m.max_cnt = g.cnt) v ON s.shop_id = v.shop_id WHERE s.publish = 1

How to show only the id of one table and not to duplicate with other tables?

I have 6 tables and 3 of them is what I need to show in my table and the other 3 is what I needed to hide in the same table.
Report:
id name branch comp_id start_date end_date
100 A 001 011 2022-08-14 2022-08-14
200 B 002 012 2022-08-14 2022-08-14
Report Details:
id product_id product_code price deliveries
100 01 11 20.00 10
100 01 11 20.00 10
200 01 11 20.00 20
200 02 12 25.00 20
Products:
id code name
01 11 Prod 1
02 12 Prod 2
Product Details:
id code name Desc
01 11 Prod 1 Desc 1
02 12 Prod 2 Desc 2
Branches:
id code name
001 021 Branch 1
002 022 Branch 2
Companies:
id name branch
011 Company 1 021
012 Company 2 022
I want the output to be like this:
id: will come from reports table
branch_name: will come from branches table using the branch in report table
company_name: will come company using the comp_id in report table
product_name: will come from products table using product_id in report details table
description: will come from product_details table using product_code in report details table
start_date: will come from report table
end_date: will come from report table
id branch_name company_name product_name description start_date end_date
100 branch 1 Company 1 Prod 1 Desc 1 2022-08-14 2022-08-14
200 branch 2 Company 2 Prod 1 Desc 1 2022-08-14 2022-08-14
200 branch 2 Company 2 Prod 2 Desc 2 2022-08-14 2022-08-14
I have this sql and it all shows the id in report details table:
SELECT *, `acc`.`name` AS `cname`, `out`.`name` AS `outname`, `pro`.`name` AS `pname`, `prod`.`name` AS `sname`
FROM `report` AS `rep`
JOIN `companies` AS `acc` ON `rep`.`account_id`=`acc`.`code`
JOIN `branches` AS `out` ON `rep`.`outlet_id`=`out`.`code`
JOIN `report_details` AS `red` ON `rep`.`report_id`=`red`.`report_id`
JOIN `products` AS `pro` ON `red`.`product_id`=`pro`.`id`
JOIN `product_details` AS `prod` ON `red`.`sku_id`=`prod`.`id`
Try this:
SELECT R.id, B.name AS branch_name, C.name AS company_name, PD.product_name AS product_name, PD.Desc AS description, R.start_date
FROM Report R
LEFT JOIN report_details RD ON R.id = R.id
LEFT JOIN products P ON RD.product_id = P.id
LEFT JOIN product_details PD ON PD.product_id = PD.id
LEFT JOIN branches B ON R.branch = B.id
LEFT JOIN companies C ON R.comp_id = C.id
GROUP BY R.id, B.name, C.name, PD.product_name, PD.Desc, R.start_date

MySql duplicate SUM, one to many relation ship

I have following 3 tables where B, C have many to one relation ship with A, and i need to generate the following Result table with MySql
Table A Table B Table C
id name id A.id qty id A.id
1 a 1 1 5 1 1
2 b 2 1 10 2 1
3 c 3 2 4 3 2
4 3 6 4 2
5 2 7
Expected Result Table
C.id A.id sum(B.qty Group by A.id)
1 1 15
2 1 15
3 2 11
4 2 11
select c.id, a.id, sum(b.qty)
from c
inner join a on c.a_id = a.id
inner join b on b.a_id = a.id
group by c.id, a.id
or in your case, you just don't need table a
select c.id as cid, c.a_id as aid , sum(b.qty) as totalqty
from c
inner join b on b.a_id =c.a_id
group by c.id, c.a_id;