SQL: how do i find customer orders with customers? - mysql

I have two tables:
1. customer
2. customer_order
Customer table contains customer data(duh) and customer_order contains all the orders.
I can join them on customer.id=customer_order.id_customer.
All fine, but now i want a query, where i have all the customer ids, and next the orders(customer_order.id) which these customers made (with order date)
like this:
customer 100 order 4, order 5, order 9
customer 101 order 7, order 8, order 15
I have this, but doesn't give me the result, it puts all the customer ids with an order on different rows:
SELECT c.id, c.firstname, co.id
FROM customer c
JOIN customer_order co
ON c.id=co.id_customer
;

You can use the group_concat function
select c.id, c.firstname, GROUP_CONCAT(co.id SEPARATOR ',')
from custom c
join custom_order co
group by c.id
this would return something like
customer 100 | 4,5,9
customer 101 | 7,8,15

Have you tried:
SELECT c.id, c.firstname, co.id
FROM customer c
INNER JOIN customer_order co
ON c.id=co.id_customer
ORDER BY c.id;
It's either LEFT or INNER, you'll get different results depending on which you use, and I think for your purposes LEFT is the one you want to use. Then when you retrieve the data, you might have to drop it into:
array["custid"][] = co.id

Related

mysql count rows from two tables in one query?

I have two MySQL-tables:
Persons (pid,name,companyID,companyName)
Orders (oid,companyID,details)
Now I want to count the number of order_id for each companyName as following:
Name Total
-------------------
CompanyName1 : 1200
CompanyName2 : 758
CompanyName3 : 11
I used this query but it's not working properly.
SELECT count(o.oid) as total,p.companyName
FROM orders as o, persons as p
WHERE o.companyID = p.companyID
GROUP BY p.companyName
Use join and group the result by p.companyID
SELECT p.companyName, count(o.oid) as total
FROM orders as o join persons as p
on o.companyID = p.companyID
GROUP BY p.companyID
If you are missing the companies without any orders you can use a left join.
SELECT p.companyName, count(*) as total
FROM persons p
LEFT JOIN orders o ON o.companyID = p.companyID
GROUP BY p.companyID, p.companyName
Please do not use the old, legacy join syntax any more - it is outdated since 1992.
Your data model looks messed up. That you have company ids and names in the person table but no corresponding companies table is highly suspicious.
In any case, presumably there can be multiple rows per company. You can condense the persons table and then join:
SELECT c.companyName, COUNT(*) as total
FROM orders o JOIN
(SELECT DISTINCT companyId, companyName
FROM persons p
) c
ON o.companyID = c.companyID
GROUP BY c.companyName;
However, you should fix the data model so you have a real bona fide companies table -- especially because you seem to care about that entity.

Ordering rows in a parent table by SUM of column in a child table

I have 3 tables in my database
companies{
id,
name,
address
}
stores{
id,
name,
address,
company_id
}
invoices{
id,
total,
date_time,
store_id
}
As you can see, each store is connected to a company via foreign key, also each invoice is connected to a store.
My question is, how can i write a SQL query which will return all stores by a company and order them by their turnover?
If i use the query:
SELECT s.*,
sum(i.total) as turnover FROM store s
JOIN invoices i
ON i.store_id = s.id
WHERE YEAR(i.date_time) = 2019;
I can see the turnover for one store for a year 2019 for example, but i'm struggling to find a way to get a list of store ordered by their turnover for a certain period.
You're going to need to join all 3 tables:
SELECT *
FROM
companies c
INNER JOIN stores s on s.company_id = c.id
INNER JOIN invoices i ON i.store_id = s.id
That's your entire raw data in detailed list. Then you say you want it for a certain company only:
SELECT *
FROM
companies c
INNER JOIN stores s on s.company_id = c.id
INNER JOIN invoices i ON i.store_id = s.id
WHERE c.name = 'Acme Rubber Co'
Then you only want the stores and the invoices amounts:
SELECT s.name, i.total
FROM
companies c
INNER JOIN stores s on s.company_id = c.id
INNER JOIN invoices i ON i.store_id = s.id
WHERE c.name = 'Acme Rubber Co'
Then you want a row set where each line is a single store and the sum of all invoices for that store:
SELECT s.name, SUM(i.total)
FROM
companies c
INNER JOIN stores s on s.company_id = c.id
INNER JOIN invoices i ON i.store_id = s.id
WHERE c.name = 'Acme Rubber Co'
GROUP BY s.name
Lastly you want them in descending order, highest total first:
SELECT s.name as storename, SUM(i.total) as turnover
FROM
companies c
INNER JOIN stores s on s.company_id = c.id
INNER JOIN invoices i ON i.store_id = s.id
WHERE c.name = 'Acme Rubber Co'
GROUP BY s.name
ORDER BY turnover DESC
The order of evaluation in sql is FROM(with joins), WHERE, GROUP BY, SELECT, ORDER BY which is why I use different names in eg the order by than I do in the group by. Conceptually your db only sees the names of things as output by the immediately previous operation. Mysql isn't actually too picky but some db are - you couldn't say GROUP BY storename in sql server because the SELECT that creates the storename alias hasn't been run at the time the group by is done
Note: I wasn't really sure on what you were looking for in a WHERE - you started by saying "all stores turnover for a certain company" and finished saying you were "struggling to get turnover for a period"
If you want a period, use eg WHERE somedatecolumn BETWEEN '2000-01-01' AND '2000-12-31' (Between is inclusive) or WHERE somedatecolumn >= '2000-01-01' AND somedatecolumn < '2001-01-01' (A good pattern to use if the date includes a time too). It is almost never wise to call a function on a column you're searching with, ie do not do WHERE YEAR(somedatecolumn) = 2000 because it disables indexing on the column and makes the search very slow

How can I use COUNT and GROUP BY in MYSQL while still displaying all individual rows?

I am just trying some practise exercises with MYSQL. I have a dataset where I would like to get the names of customers who ordered two or more different kinds of item and how many of each kind of item they bought.
The query below gives me a row for each name of the purchaser. However, I also want to display what types of items they bought and how many of them. Ideally I would like to have the same number of rows for each customer for how many different items they bought.
SELECT firstname, familyname, description, quantity
FROM customers c
JOIN orders o ON o.custID = c.custID
JOIN lineitems l on o.orderID = l.orderID
JOIN items i on l.itemID = i.itemID
GROUP BY firstname
HAVING count(description)
The query below does give me a row for each item, how many items that person bought, and the name of the purchaser. However, it does not filter for customers who only bought one specific item anymore.
SELECT firstname, familyname, description, quantity
FROM customers c
JOIN orders o ON o.custID = c.custID
JOIN lineitems l on o.orderID = l.orderID
JOIN items i on l.itemID = i.itemID
WHERE EXISTS(
SELECT *
FROM customers
GROUP BY firstname
HAVING count(description) >= 2)
Basically I would like to combine both approaches where there are multiple rows for specific item for each customer, while also filtering out customers who only bought one type of item.
If you are running MySQL 8.0, you can do a window count in a subquery and filter in the outer query, like:
SELECT *
FROM (
SELECT
c.firstname,
c.familyname,
i.description,
l.quantity,
COUNT(*) OVER(PARTITION BY c.custID) cnt
FROM customers c
JOIN orders o ON o.custID = c.custID
JOIN lineitems l on o.orderID = l.orderID
JOIN items i on l.itemID = i.itemID
) x
WHERE cnt > 1
Note: it is a good practice to prefix column names with the alias of the table they belong to; this makes the query more readable and avoid clashes when the same column name exists across tables. I made a few assumptions and updated the query accordingly.

Mysql + difference in two result sets

I have a pretty simple MySQL question. I have two tables, Customer and Orders. Customer table has fields (id, name) and Order has fields (id, customerID, and item).
I can find which customer bought product A and customers that bought product B with the following query in MySQL.
SELECT DISTINCT c.`id`, c.name, o.`item`, o.qty FROM `customer` as c
INNER JOIN order AS o ON (c.`Id` = o.`customerID`)
where o.`item` ="Product A"
Union
SELECT DISTINCT c.`id`, c.name, o.`item`, o.qty FROM `customer` as c
INNER JOIN order AS o ON (c.`Id` = o.`customerID`)
where o.`item` ="Product B"
How can find the difference and similarity in these two result sets?
1) I.e. Customers that bought only product A but did not by product B
2) I.e. Customers that bought both product A and B
Thank you for your assistance.
D
You can try using the LEFT OUTER JOIN to get the result.

SQL query within another query

I have a table containing customers and another containing all orders.
I want to display a list of customers and along side show the total value of their orders.
Obviously I could loop through the customers and then using PHP run another query to get each customer's revenue. I don't think this is efficient.
I am looking to achieve something like this:
SELECT username, [SELCT sum(revenue) from orders where userID=userID] from customers
And for this to show output:
bob 10000
jeff 25000
alan 500
SELECT a.username, SUM(b.revenue) totalRevenue
FROM customers a
LEFT JOIN Orders b
ON a.userID = b.UserID
GROUP BY a.username
This will list all customers with or without Orders.
To further learn more about join, please visit the article below,
Visual Representation of SQL Joins
you're close...
SELECT username, (SELECT sum(revenue) from orders where userID=c.userID) rev
from customers c
You can join the tables and the group them by the order name
SELECT o.username,
sum(revenue) as sum_revenue
from orders o
left outer join customers c on c.userid = o.userid
group by o.username
No need for a subselect with that. Try something like this:-
SELECT customers.userID, customers.username, SUM(revenue)
FROM customers INNER JOIN orders ON customers.userID = orders.userID
GROUP BY customers.userID, customers.username