Select data with a join from 3 tables - mysql

I just started learning SQL now and trying to figure out this scenario:
We have 3 tables:
Clients (ClientID, Name, Surname, Age)
Products (ProductID, Name, Price)
Purchases (PurchaseID, Date, ClientID, ProductID)
What would be the best SQL query that will show the amount of purchases (total amount per client) made by clients?
It must only show the clients who made more than 1 purchase.
The result should contain the following fields: Full name, Quantity of purchases, Total amount.
I've got this query but it only joins two tables. How do I join the third table (Products.Price) as well and calculate the total amount per client?
SELECT CONCAT(IFNULL(Name,''),' ', IFNULL(Surname,'')) as FullName,
COUNT(purchaseId) as "Quantity of purchases"
FROM Purchases as P
INNER JOIN Clients as C
on P.ClientID = C.ClientID
GROUP BY C.ClientID,Name, Surname
HAVING COUNT(PurchaseId) > 1;

I would recommend that you use CONCAT_WS() to combine the first name. This handles NULL values more elegantly than your solution.
SELECT CONCAT_WS(c.Name, c.Surname) as FullName,
COUNT(*) as num_purchases,
SUM(pr.price) as total_price
FROM Clients c INNER JOIN
Purchases p
ON P.ClientID = C.ClientID INNER JOIN
Products pr
ON pr.ProductID = p.ProductID
GROUP BY CONCAT_WS(c.Name, c.Surname)
HAVING COUNT(DISTINCT p.PurchaseId) > 1;
Note the COUNT(DISTINCT) in the HAVING clause. This ensures that the clients have at least two purchases. If you only want clients with at least two products or purchases, then you can use COUNT(*) -- but your question is about purchases.

You can try below -
SELECT CONCAT(IFNULL(Name,''),' ', IFNULL(Surname,'')) as FullName,
COUNT(purchaseId) as "Quantity of purchases",sum(price) as totalamount
FROM Purchases as P
INNER JOIN Clients as C
on P.ClientID = C.ClientID
inner join Products p1 on p.productid=p1.productid
GROUP BY C.ClientID,Name, Surname
HAVING COUNT(PurchaseId) > 1

Related

Select From multiple tables and relate with COUNT

first sorry, i don't have fluid english.
I want select 3 rows in 3 different tables, two of them without Foreing Key/relation.
Need to select amount of customers in each store, and total amount of payments in these stores in one query.
Here are the tables:
Customers
Stores
Payments
I have tried these querys to get payments for each store and customers for each store, but don't know how can unify in one query:
Payments/store
SELECT count(a.payment_id) as alquileres, b.store_id
FROM customer b, payment a
WHERE a.customer_id = b.customer_id
GROUP BY b.store_id;
customers/store
SELECT count(customer_id), store_id
FROM customer
GROUP BY store_id;
But when I add count(customer_id) in unique query don't have same results.
You can use one query:
select c.store_id,
count(distinct c.customer_id) as num_customers,
count(p.payment_id) as num_payments
from customers c left join
payments p
on p.customer_id = c.customer_id
group by c.store_id;

Sql query to fetch multiple data from multiple tables

Given the following tables:
• Clients (ClientId, Name, Surname, Age)
• Products (ProductId, Name, Price)
• Purchases (Purchaseld, Date, ClientId, Productid)
I need to write an SQL query that shows the quantity of purchases made by clients. It must only show the clients who made more than 1 purchase. The result should contain the following fields: Full name (i.e. "john rambo"), Quantity of purchases.
I have written this query but results are not coming correct
SELECT Concat(clients.name, clients.surname)
FROM clients
JOIN products
ON clients.name = products.name
JOIN purchases
ON products.productid = purchases.productid
GROUP BY clientid
HAVING Count(clientid) > 1
SELECT Concat(clients.name, ' ', clients.surname),
count(*) as number_of_orders
FROM clients
JOIN purchases
ON products.productid = purchases.productid
GROUP BY Concat(clients.name, ' ', clients.surname)
HAVING Count(clientid) > 1
As noted in the comments, your join to products doesn't make much sense - your asking to only return records where there's a product that matches a client's first name.
CONCAT will glue the two fields together (e.g. "JohnRambo")
It must only show the clients who made more than 1 purchase.
Your question has no mention of products, so there is no need for that in the query:
SELECT CONCAT(c.name, c.surname)
FROM clients c JOIN
purchases p
ON p.ClientId = c.ClientId
GROUP BY c.ClientId, CONCAT(c.name, c.surname)
HAVING COUNT(*) > 1 ;
Note that the ClientId presumably uniquely defines the clients -- not the names. So the ClientId should be part of the aggregation.

MySQL - Calculation of invoice balance grouped by client using 3 tables

I'm currently working on a small client management system and I came accross a feature I can't yet get to work in pure SQL (currently using PHP foreach with lot of lazy loading, so very slow).
I am trying to get the current balance of each clients, so getting the sold of each invoice (by substracting SUM of payments) payment and SUM them. Each clients has invoices in the systems and each invoices can have multiple payments.
Here's my simplified tables for the purpose of being generic:
[Clients]
- id
- name
[Invoices]
- id
- client_id
- amount
[Payments]
- id
- invoice_id
- amount (positive number)
So basically, I want to get this:
+--------------------+----------------------+
| name | balance |
+--------------------+----------------------+
| Client 1 | 342,46 |
| Client 2 | 0,00 |
+--------------------+----------------------+
To get the invoice sold, I need SUM(invoices.amount) - SUM(payments.amount)) but my query isn't working at all. Here's what I got so far:
SELECT DISTINCT
c.name,
SUM(x.sold) AS balance
FROM
clients AS c
RIGHT JOIN
(
SELECT SUM(i.invoiceAmount - total_payments) AS sold
FROM invoices
WHERE i.client_id = c.id
RIGHT JOIN (
SELECT p.id, p.invoice_id, SUM(p.transactionAmount) AS total_payments
FROM payments AS p
GROUP BY p.invoice_id
) AS p ON p.invoice_id=i.id
GROUP BY i.client_id
) AS x ON x.client_id=c.id
GROUP BY c.name
ORDER BY c.name ASC
Does anybody ever done this before? I never did and it's pretty tricky.
Note: I tried to be as much generic as possible, so it may help other people in a similar situation.
UPDATE:
Using #GordonLinoff answer, I was able to get what I wanted using the query he provided me.
select name, SUM(invoices - IFNULL(payments, 0)) as balance
from (
select name, sum(amount) as invoices, sum(payments) as payments
from (select c.id, c.name, i.id as invoiceid, i.amount, sum(p.amount) as payments
from clients c left join
invoices i
on c.id = i.client_id left join
payments p
on p.invoice_id = i.id
group by c.id, c.name, invoiceid, i.amount
) ci
group by name
) x
The result is exactly as I expected.
Aggregating through hierarchical structures is tricky. Here is one method that joins the tables together and then uses two levels of aggregation:
select name, sum(amount) as invoices, sum(payments) as payments
from (select c.id, c.name, i.id, i.amount, sum(p.amount) as payments
from clients c left join
invoices i
on c.id = i.client_id left join
payments p
on p.invoice_id = i.id
group by c.id, c.name, i.id, i.amount
) ci
group by name;

Selecting a summed value from a subquery that relies on a joined table

So I'm the lucky guy who gets to optimize a query for our application that's taking far too long for the data we're getting. The data we're looking for isn't significantly complex, but the crappy database design is making it a lot harder then it should be (which is great, because I'm the one who designed it about a year ago).
The general idea is we're trying to calculate the total sales (they buy something that increases their balance) and the total payments (they paid money against their balance) for each customer.
The tables:
Customers
id
company
Sales (invoices):
id
customer_id
Payments (account_payments)
id
customer_id
transaction_id (links to invoice_transactions)
Transactions (invoice_transactions)
id
invoice_id (links to invoices, null if payment)
amount
If a user makes a sale, the info is recorded in invoices and invoice_transactions, with invoice_transactions having the invoice_id of the invoices record that contains the customer_id.
If the user makes a payment, the info is recording in account_payments and invoice_transactions, with invoice_transaction having an invoice_id of NULL, and account_payments containing the transaction_id as well as the customer_id.
I know, it's horrible... And I thought I was being clever! Well, I thought the problem through, and came up with a decent solution:
SELECT SQL_NO_CACHE
c.company,
(SELECT SUM(amount) FROM sales),
(SELECT SUM(amount) FROM payments)
FROM customers c
JOIN invoices i ON i.customer_id = c.id
JOIN invoice_transactions sales ON i.invoice_id = sales.id
JOIN account_payments ap ON ap.customer_id = c.id
JOIN invoice_transactions payments ON ap.transaction_id = payments.id
Which does absolutely nothing except give me an error "#1146 - Table 'db.sales' doesn't exist". I'm guessing it has something to do with sub queries being read prior to joins, but I honestly have no idea. And unfortunately I have no idea of another way to approach this problem... Much appreciated if anyone could give me a hand!
I think the best approach would be to separate the the elements Sales and Payments into subqueries, your current method is cross joining all payments with all invoices before doing the aggregation.
SELECT c.ID,
c.Company,
COALESCE(Sales.Amount, 0) AS Sales,
COALESCE(Payments.Amount, 0) AS Payments
FROM Customers c
LEFT JOIN
( SELECT Customer_ID, SUM(Amount) AS Amount
FROM Invoices
INNER JOIN invoice_transactions
ON Invoice_ID = Invoices.ID
GROUP BY Customer_ID
) As Sales
ON Sales.Customer_ID = c.ID
LEFT JOIN
( SELECT Customer_ID, SUM(Amount) AS Amount
FROM Account_Payments
INNER JOIN invoice_transactions tr
ON tr.ID = Transaction_ID
GROUP BY Customer_ID
) AS Payments
ON Payments.Customer_ID = c.ID;
This will include customers with no invoices and no payments. You can change the left joins to inner joins to manipulate this.
Working Example on SQL Fiddle
Your query doesn't make sense.
After doing all the joining, why not just use the tables in the "from" clause:
SELECT c.company, SUM(sales.amount), SUM(payments.amount)
FROM customers c JOIN invoices i ON i.customer_id = c.id JOIN
invoice_transactions sales ON i.invoice_id = sales.id JOIN
account_payments ap ON ap.customer_id = c.id JOIN
invoice_transactions payments ON ap.transaction_id = payments.id
group by c.company
Just giving a table an alias in the "from" clause does not make it available in subqueries elsewhere in the query.
I also added a GROUP BY clause, since your query seems to be aggregating by company.

A SQL query that does not work for getting number of orders in a table

This is a part of SQL coding project of database.
I need to design a single table to hold orders made by customers.
Assume that customers' details (e.g. names) are stored in another table.
Using the table that I designed for orders, and this assumed other table, write
a single SQL query that can give the number of orders for every customer, one line per customer.
The “Orders” table
Order_ID Order_NO Customer_ID
1 8088 3
2 9632 1
3 1272 4
4 6037 1
Assume that the customer names and other details (address, phone numbers, emails) are stored in the “Customers” table.
My SQL:
SELECT Customers.FirstName, Customers.FirstName, Orders.OrderNo
FROM Customers
FULL JOIN Orders
ON Customers.Customer_ID = Orders.Customer_ID
ORDER BY Customers.LastName
Are there something wring with it ?
Change the query to inner join
SELECT
Customers.FirstName
, Customers.FirstName
, Orders.OrderNo
FROM
Customers
INNER JOIN Orders ON Customers.Customer_ID = Orders.Customer_ID
ORDER BY
Customers.LastName
Query for Ordercount for customer
SELECT
Customers.LastName
, COUNT(Orders.Order_Id)
FROM
Customers
INNER JOIN Orders ON Customers.Customer_ID = Orders.Customer_ID
GROUP BY
Customers.LastName
ORDER BY
Customers.LastName
Full join
http://www.w3schools.com/sql/sql_join_full.asp
Inner join
http://www.w3schools.com/sql/sql_join_inner.asp
If you just want to COUNT the orders you can do this:
SELECT
Customers.FirstName,
(
SELECT
COUNT(*)
FROM
Orders
WHERE
Orders.Customer_ID=Customers.Customer_ID
) AS NbrOfOrders
FROM
Customers
References:
12.15.1. GROUP BY (Aggregate) Functions
Don't forget COUNT and GROUP BY.