Correlated Subquery to determine Customer Records - mysql

I have two tables, customer and customer_order
Customer
cust_id, cust_name
121 Acme Wholesalers
234 Griffen Electric
336 East Coast Marine Supplies
544 Sanford Automotive
Customer_Orders
order_num,cust_id,order_date
1 121 2019-01-15
2 234 2019-07-24
3 336 2020-05-02
4 121 2019-01-15
5 336 2020-03-19
6 234 2019-07-24
7 121 2019-01-15
8 336 2020-06-12
I need to write a query that returns the name of the customer who has placed exactly 3 orders. I cannot return the same customer name than once and I must use a correlated subquery against the customer_order table.
So far I have the following, which returns all four customers.
select c.cust_name
from customer c
where exists
(select count(*)
from customer_order co
where c.cust_id = co.cust_id);
I need to add the = 3 qualifier but not sure where.

Try this:
select c.cust_name, count(co.id) as num_orders
from customer c join customer_order co on c.cust_id = co.cust_id
group by c.cust_name
having num_orders = 3;
I am assuming, that cust_name is unique, else you must group by cust_id.

Related

MySQL Join AND SUM on Both Tables

I'm trying to join two tables and sum the results from both tables columns but I can't figure out. I'm doing it in Joomla.
invoices table:
id
owner
amount
1
123
300.00
2
123
125.00
3
144
200.00
4
166
155.00
expenses table:
id
owner
amount
1
123
10.00
2
123
50.00
3
144
50.00
results:
owner
invoices
expenses
123
425.00
60.00
144
200.00
50.00
166
155.00
0.00
This should give you the expect results. I do LEFT JOIN for results from both tables.
SELECT l.`owner`, invoices, IFNULL(expenses,0) FROM
(
SELECT
`owner`, SUM(amount) AS invoices
FROM
invoices
GROUP BY
`owner`
) AS l LEFT JOIN (
SELECT
`owner`, SUM(amount) AS expenses
FROM
expenses
GROUP BY
`owner`
) AS r ON l.`owner` = r.`owner`

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

How to concat rows in a MySQL query?

I`m running this query below:
SELECT a.id as id_order, b.id as id_service,
d.nome as service_name,
c.dente as tooth,
(SELECT count(c.dente)
FROM labpedidoservicodente c
WHERE b.id = c.idLabPedidoServico) AS total,
e.valorServico as cost
FROM labpedido a
INNER JOIN labpedidoservico b
ON a.id = b.idLabPedido
INNER JOIN labpedidoservicodente c
ON a.id = c.idLabPedido
INNER JOIN labservico d
ON b.idLabServico = d.id
INNER JOIN labservicovalor e
ON b.idLabServico = e.idLabServico
WHERE a.id = '914'
My result comes this way:
order_id service_id service_name tooth total cost
914 640 SERVICE NAME 1 11 3 80.00
914 640 SERVICE NAME 1 21 3 80.00
914 640 SERVICE NAME 1 38 3 80.00
914 641 SERVICE NAME 2 11 3 84.80
914 641 SERVICE NAME 2 21 3 84.80
914 641 SERVICE NAME 2 38 3 84.80
My desired output should be like this:
order_id service_id service_name tooth total cost
914 640 SERVICE NAME 1 11-21 2 80.00
914 641 SERVICE NAME 2 38 1 84.60
The problem is that I need to concat these rows in the column "tooth" inside their respective "service_id", have tried everything but no sucess, also the total
Replace c.dente with GROUP_CONCAT(c.dente SEPARATOR ' - ') and add GROUP BY service_id below.

Mysql Fetch Records When Foreign Key Value Is Zero

I've created some tables as follows.
countries
con_id con_name
99 India
100 China
cities
cty_id cty_name country_id
1 Bangalore 99
2 Chennai 99
3 Delhi NCR 99
fees
f_id st_dt end_dt city_id country_id
1 2014-05-05 2014-05-05 1 99
2 2014-05-10 2014-05-10 2 99
3 2014-05-15 2014-05-15 3 99
4 2014-05-20 2014-05-20 0 100
5 2014-05-22 2014-05-22 0 100
I'm writing a query fetch the records from fees table by country_id as follows.
SELECT *
FROM fees as fe
JOIN countries as con
ON con.con_id = fe.country_id
JOIN cities as cty
ON cty.cty_id = fe.city_id
For country india, it fetches first 3 records from fees table and for country china, its not fetching any records due to joinings.
So I want the results like null for city columns and correct values for fees and country tables.
Please help me how to get the solution for this. The work would be more appreciated.
You can use LEFT JOIN (or right, depending on the join sequence):
SELECT *
FROM countries c
LEFT JOIN fees f
ON c.con_id = f.country_id
LEFT JOIN cities ci
ON ci.country_id = c.con_id
The left join will fill with nulls the columns which don't have a match in the join.

How to combine many to many join?

Tables:
cust table:
cust_id, name, etc
bill table:
bill_id, cust_id, amt, due_date, status (open/closed)
payment table:
payment_id, bill_id, amt etc
Customer can settle a single bill by paying multiple installments. So, one bill_id may relate to payment_ids.
I am unable to generate this recordset:
cust_id | due amt
'due amt' is the sum of all bill.amts - sum of all payment.amts and having status open.
Bill table
bill_id cust_id amt status
1 18 200 open
2 18 200 open
3 17 200 open
4 17 200 open
5 17 200 open
6 17 200 closed
Payment table
payment_id bill_id cust_id amt
1 1 18 50
2 2 18 40
3 3 17 10
Expected output
cust_id due_amt hint/how
17 590 (600-10) .. 600 -> because one is closed
18 310 (400-(50+40))
select c.cust_id, sum(b.amt) - sum(p.amt) as due_amt
from cust c
left join bill b on b.cust_id = c.cust_id and b.status = 'open'
left join payment p on p.bill_id = b.bill_id
group by c.cust_id
SQLFiddle demo