A cleaner way to do this SQL query - mysql

So have a list of customers, that have a list of customers.
I have 2 tables, customers and invoices.
Customer_id can be the same for my customers e.g
Client A
Customer #1
Client B
Customer #1
So invoice table can have customer_id of 1, for different customers.
The below query works, but seems a little messy. Any ideas to clean it up?
SELECT name,
sum(sub_total) total
FROM customers, invoices
WHERE customer_id = 1438 and
invoices.customer_id = 1438 and
customers.customer_id = invoices.customer_id
GROUP BY name
Order By total DESC;

If A = B and A = 1438 then B = 1438 you don't need to check it...
(Trust me on this one, I got 60+ in math in highschool)
SELECT name, sum(sub_total) total
FROM customers, invoices
WHERE invoices.customer_id = 1438
AND customers.customer_id = invoices.customer_id
GROUP BY name
ORDER BY total DESC;
Or with explicitly saying which type of JOIN you want:
SELECT name, sum(sub_total) total
FROM customers INNER JOIN invoices
ON customers.customer_id = invoices.customer_id
WHERE invoices.customer_id = 1438
GROUP BY name
ORDER BY total DESC;

you dont need the extra check...
SELECT name, sum(sub_total) total
FROM customers, invoices
WHERE
customer_id = 1438 and
customers.customer_id = invoices.customer_id
GROUP BY name order by total DESC;

I would strongly NOT do a group by on name... Say you have two customers named "Bill Smith", but one is customer ID 10, and the other is customer ID 785... You just combined them into a single person. You SHOULD be grouping by ID, not the name...
Now, that said, you are querying for only a single customer ID anyhow and will only ever return a single record. If what you are really trying to accomplish is getting ALL customers and the tot of their respective invoices, remove the where clause of the single customer. You can keep the group by ID, but show the actual customer's name. If you have multiple customers with the same total, you can sub-sort by their name, but the grouping is STILL based on just the customer's ID.
SELECT
c.name,
sum(i.sub_total) total
FROM
customers
JOIN invoices
on c.Customer_ID = i.Customer_ID
GROUP BY
c.customer_ID
Order By
total DESC,
c.Name

Related

SQL How to find which customer has rented the most films?

I'm struggling with a question that said Which customer has rented the
most films?
I am doing this using the Seikila sample database in MySQL. I have something that joins my tables together and attempts to give me a count but I know its wrong just looking at the actual data in the rental table.
my code is as below
SELECT r.rental_id, cust.customer_id, count(*) as Total_Rentals
FROM rental as r
INNER JOIN customer AS cust on r.customer_id = cust.customer_id
GROUP BY cust.customer_id;
but it tells me for example customer 1 has rented 32 movies, which I know is wrong. what am I doing wrong?
since I was asked for clarification, the database I am using is:
https://dev.mysql.com/doc/sakila/en/
And I am trying to find which customer has rented the most films, I am not entirely sure what my script is actually returning.
Remove the column rental_id from the select list and sort the result by count(*) descending to return the top 1 row:
SELECT cust.customer_id, cust.name, count(*) as Total_Rentals
FROM rental as r
INNER JOIN customer AS cust on r.customer_id = cust.customer_id
GROUP BY cust.customer_id, cust.name
ORDER BY Total_Rentals DESC LIMIT 1
But if you only need the customer's id then there is no need for a join:
SELECT customer_id, count(*) as Total_Rentals
FROM rental
GROUP BY customer_id
ORDER BY Total_Rentals DESC LIMIT 1
You need to join customer and rental, group by customer id (without rental id) and count it:
SELECT cust.customer_id, count(*) as Total_Rentals
FROM rental as r
INNER JOIN customer AS cust on r.customer_id = cust.customer_id
GROUP BY cust.customer_id;
So this code should work. If it doesn't work, that probably means that you have duplicates or other nonconventional issues.

Working with multiple tables

I have these 4 tables with different rows and columns and I need to get certain values. I am having some difficulty with a few and cannot seem to get it.
customers table:
customerID: integer
fName: string
lName: string
items table:
itemID: integer
description: string
price: float
orders table:
orderID: integer
itemID: integer
aID: integer
customerID: integer
date: date
addresses table:
aID: integer
housenum: integer
streetName: string
town:string
state: string
zip:integer
The values I am looking to get are:
List the itemID and description of all items for which there is only one order.
Now I can get the itemID and description, however I am not sure how to nail it down to items only ordered once. I am thinking of using JOIN and GROUP BY but I cannot seem to find the correct combination.
SELECT itemID,
description
FROM items
GROUP BY itemID
List all customers who have shipped items to multiple addresses.
This one I have to use JOIN somehow, since the customerID would be the same but not the address?
SELECT customerID,
streetName,
housenum
FROM addresses
JOIN customers
ON addresses.streetName = customers.customerID
Return the total revenue generated by all of the orders.
Couldn't I just use:
SELECT SUM(price),
orderID
FROM items
JOIN orders
ON orders.orderID = items.price ?
List the first and last names of all customers who have had the same item shipped to at least two different addresses.
SELECT fName,
lName,
itemID,
streetName,
housenum
FROM addresses,
customers,
items,
somehow join multiple(2+)?
I may not be right with all the queries but I have found the items listed on the question very interesting and decided to give it a try.
items sold only once
SELECT o.itemID,
i.description
FROM orders o
LEFT JOIN items i
ON i.id = o.itemID
GROUP BY o.itemID
HAVING COUNT(*) = 1;
On this query, you need to join the the items table in order to retrieve the description and GROUP BY it by the itemID so you can specifically use COUNT for each itemID which we can then use with HAVING to obtain on the ones with 1 order.
Customer that have shipped to diff address
SELECT COUNT(DISTINCT addressID) as diff_address,
c.fName,
c.lName
FROM orders o
LEFT JOIN customers c
ON o.customerID = c.id
GROUP BY o.customerID
HAVING diff_address > 1;
Here I am using the DISTINCT function to eliminate duplicated address and GROUP BY the customerID so I can have a list of unique address per customer and again using HAVING we get the customers that have shipped products with more than 1 different address. Am also using JOIN on the customer table to obtain their needed information.
Total revenue
SELECT SUM(i.price) as total
FROM orders o
LEFT JOIN items i
ON o.itemID = i.id;
I guess this one is the simplest one here, by using JOIN on the items table, I am able to read each item price which I can then sum per order to have a gran total of sales.
List of customers that have shipped the same item to at least 2 different address
SELECT c.fName,
c.lName,
COUNT(oi.itemID) AS `total items with diff address >= 2`
FROM customers c
JOIN (SELECT customerID,
itemID,
COUNT(DISTINCT addressID) AS diff_address
FROM orders
GROUP BY itemID, customerID
HAVING diff_address >= 2
) AS oi
ON oi.customerID = c.id
GROUP BY c.id;
This one was the most complicated one, hope I can explain it. First I started it with the sub-query where I can list all items per customer that have multiple address, then by using JOIN on the customerID I can count how many different items that given customer have shipped with 2 or more diff address.
Here is a LIVE DEMO.
If you see any of the queries are not good or have any advice kindly do tell me so I can improve it.

Find customers with more than 1 order grouped by day

I want to know how many customers placed more than 1 order, grouped by day.
But I want to exclude orders that have been cancelled.
I have a customer table with customers
I have a customer_order table with orders (when an order is cancelled
it stays in the customer_order table)
I have an order_item table (where original orders are, and also
cancelled orders, cancelled orders get a new credit order, and the
original order id appears in the id_credit_order row of the credit
order)
I want something like this:
date | no of customers with 1 order | no of customers with 2 orders | no of customers with 3 order | etc.
But I want no count if the original order has been cancelled!
I have now this query, but its definitely not enough, does someone know how to get my result? thanks!
SELECT DATE(co.date_order), COUNT(co.id_customer)
FROM customer_order co
GROUP BY DATE(co.date_order)
ORDER BY DATE(co.date_order) DESC;
The question is slightly misleading, as you first ask for the number of customers with more than one order, then you ask for the number of customer with each of 1, 2, 3... orders.
Here's something that will give you the numbers, but unpivoted. You'll need to put the right column name in for o.id
Select -- outer query takes each order count and counts how many customers have that many
co.date_order,
co.customer_order_count,
count(*) as customer_count
From (
Select -- inner query counts how many valid orders each customer has
o.date_order,
o.id_customer,
count(*) as customer_order_count
From
customer_order o
Where
o.id_credit_order is null and -- rule out credit orders
not exists ( -- rule out orders with related credit orders
select
'x'
from
customer_order c
where
c.id_credit_order = o.id -- column name isn't mentioned in the question
)
Group By
o.date_order,
o.id_customer
) co
Group By
co.date_order,
co.customer_order_count
Order By
co.date_order desc,
co.customer_order_count
Try using a HAVING clause.
SELECT DATE(co.date_order), COUNT(co.id_customer)
FROM customer_order co
WHERE co.Cancelled = 0
GROUP BY DATE(co.date_order)
HAVING COUNT(co.id_customer) >= 1
ORDER BY DATE(co.date_order) DESC;
Give this a try. Change the WHERE to reflect how you cancel orders.
SELECT DATE(co.date_order), COUNT(co.id_customer)
FROM customer_order co
WHERE co.cancelled = 0
GROUP BY DATE(co.date_order)
HAVING COUNT(co.id_customer) > 0
ORDER BY DATE(co.date_order) DESC;

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.

Need help get following query

I have three tables customer, customer_account, account_transaction
Table structure is as follow -
Customer
Id,
Branch,
Name
..
customer_account
Id,
Cust_id,
Loanamout,
EMI
account_transaction
ID,
account_id,
amount,
date
I need to get branch wise details in form of count of Loan given, sum of loan given, and sum of emi received for a particular branch. below is my current query -
SELECT
count(s.id) as cntloan,
SUM(s.Loanamout)
(
SELECT SUM(amount)
FROM account_transaction i
WHERE s.id = i.account_id
) AS curbal
From
customer as c,
customer_account as s
where c.branch = 1 and s.cust_id = c.id
It is giving me desired result for count of loan and sum of loan given. but not giving the right sum of EMI paid by customers
Can anyone help me on this.
Thanks you very much
This SQL has aggregative functions such as count and sum, so without a group by, this would not work.
SELECT customer.id,
COUNT(customer_account.id) as cntloadn,
SUM(customer_account.loan) as loan,
SUM(account_transaction.amount)
FROM customer
JOIN customer_account ON customer_account.cust_id = customer.id
JOIN account_transaction ON account_transaction.account_id = customer_account.id
GROUP BY customer.id