Find customers with more than 1 order grouped by day - mysql

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;

Related

Calculate Count of items summed up in a Group By Query

I have two tables:
Orders
======
id total_price created_on
1 100 2021-01-22
2 200 2021-01-23
Items
=====
id order_id
11 1
12 1
13 2
I want to create a query to get revenue by date. For this i'm going to sum up total price in order and grouping it up by date. Along with revenue, I also want to get total numbers of orders and items for that date. Here's a query that I wrote:
SELECT
count(orders.id) as orders,
sum(orders.total_price) as billing,
DATE(CREATED_ON) as created_on
FROM
orders
WHERE orders.deleted_on IS NULL
group by Date(orders.created_on);
Now I found 2 problems:
The count of orders is coming incorrect. Not sure what. i'm doing wrong here.
How can I calculate the count of items also in same query ?
I'm learning sql and this seems a big difficult to get my head around. Thanks for your help.
As Items.order_id is foreign key to Order.id as a result we need to join both tables first.
SELECT count(order_id) AS orders,sum(total_price) AS billing,Orders.created_on as created_on FROM Orders,(select order_id from Items) as new WHERE Orders.id=new.order_id GROUP BY created_on;
This is tricky, because when you combine the items you might multiple the revenue. One method is to aggregate the items before joining to orders:
SELECT DATE(o.Created_On) as created_on_date,
COUNT(*) as num_orders,
SUM(i.num_items) as num_items,
SUM(o.total_price) as billing
FROM orders o LEFT JOIN
(SELECT i.order_id, COUNT(*) as num_items
FROM items i
GROUP BY i.order_id
) i
ON i.order_id = o.id
WHERE o.deleted_on IS NULL
GROUP BY DATE(o.created_on);
Note: This uses a LEFT JOIN because you have not specified that all orders have items. If all do then an INNER JOIN would suffice.

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.

Need to know how to select customer names where their purchase price is greater than 100

i have a sql homework. i Have built a small database with 3 tables(in images).I need to select customer names that have purchased for more than 100 within last month.All purchases are separated.
I tried using using SUM
SELECT customer.CustomerName
FROM customer INNER JOIN
sales
ON customer.id=sales.CustomerId
HAVING SUM(sales.SalesPrice > 100)
In my database there are customers that the sum of Sales price is greteater than 0 but SQL return blank outputenter image description here
Try this:
SELECT customer.customerName FROM customer
INNER JOIN sales ON customer.id = sales.customerId
GROUP BY customerName
HAVING SUM(sales.SalesPrice) > 100;
The correct syntax looks like this:
SELECT c.CustomerName
FROM customer c INNER JOIN
sales s
ON c.id = s.CustomerId
GROUP BY c.id, c.CustomerName
HAVING SUM(s.SalesPrice) > 100;
I need to select customer names that have purchased for more than 100 within last month
SELECT C.CustomerName
FROM customer AS C INNER JOIN sales AS S ON C.id = S.CustomerId
WHERE S.SalesDate >= '20190701' AND S.SalesDate < '20190801' --within last month
GROUP BY C.CustomerName
HAVING SUM(S.SalesPrice) > 100 --Sum of purchases greater than 100
This sort of requires looking at the picture link, which should be included as part of the question, not as a link. For example, the link could expire or the link could be blocked by an organization's firewall.
The second part of this task needs me to write a query that return an item name that has the most transaction count. I need to know which ItemId.Sales has the most values. Currently I have this code
SELECT ItemName
FROM item
INNER JOIN sales ON item.id = sales.ItemID
but I need to know how to count those ItemID's and which ID has the biggest count

SQL beginner practice problems

Given two tables, orders (order_id, date, $, customer_id) and customers (ID, name)
Here's my method but I'm not sure if it's working & I'd like to know if there's faster/better way of solving these problems:
1) find out number of customers who made at least one order on date 7/9/2018
Select count (distinct customer_id)
From
(
Select customer_id from orders a
Left join customer b
On a.customer_id = b.ID
Group by customer_id,date
Having date = 7/9/2018
) a
2) find out number of customers who did not make an order on 7/9/2018
Select count (customer_id) from customer where customer_id not in
(
Select customer_id from orders a
Left join customer b
On a.customer_id = b.ID
Group by customer_id,date
Having date = 7/9/2018
)
3) find the date with most sales between 7/1 and 7/30
select date, max($)
from (
Select sum($),date from orders a
Left join customer b
On a.customer_id = b.ID
Group by date
Having date between 7/1 and 7/30
)
Thanks,
For problem 1, a valid solution might look like this:
SELECT COUNT(DISTINCT customer_id) x
FROM orders
WHERE date = '2018-09-07'; -- or is that '2018-07-09' ??
For problem 2, a valid solution might look like this:
SELECT COUNT(*) x
FROM customer c
LEFT
JOIN orders o
ON o.customer_id = x.customer_id
AND o.date = '2018-07-09'
WHERE o.crder_id IS NULL;
Assuming there are no ties, a valid solution to problem 3 might look like this:
SELECT date
, COUNT(*) sales
FROM orders
WHERE date BETWEEN '2018-07-01' AND '2018-07-30'
GROUP
BY date
ORDER
BY sales DESC
LIMIT 1;
The default format for a date in MySQL is YYYY-MM-DD, although this can be customized. You have to put quotes around it, otherwise it's treated as an arithmetic expression.
And none of your queries need to join with the customer table. The customer ID is already in the orders table, and you're not returning any info about the customers (like the name or address), you're just counting them.
1) You don't need the subquery or grouping.
SELECT COUNT(DISTINCT customer_id)
FROM orders
WHERE date = '2018-07-09'
2) Again, you don't need GROUP BY in the subquery. There's also a better pattern than NOT IN to get the count of non-matching rows.
SELECT COUNT(*)
FROM customer AS c
LEFT JOIN order AS o on c.id = o.customer_id AND o.date = '2018-07-09'
WHERE o.id IS NULL
See Return row only if value doesn't exist for various patterns to do this.
3) You can't use MAX($) in the outer query because the inner query doesn't return a column with that name. But even if you fix that, it still won't work, because the date column won't necessarily come from the same row that has the maximum. See SQL select only rows with max value on a column for more explanation of this.
You don't need a subquery at all. Use a query that returns the total sales for each day, then use ORDER BY to get the highest one.
SELECT date, SUM($) AS total_sales
FROM orders
WHERE date BETWEEN '2018-07-01' AND '2017-07-30'
GROUP BY date
ORDER BY total_sales DESC
LIMIT 1
If "most sales" is supposed to mean "most number of sales", replace SUM($) with COUNT(*).

How to get all order ID which not paid in SQL Server 2008?

I want to get all order id numbers for selected customer which not paid till now, my data show as following:
What I want is Write a SELECT statement that answers this question:
select orderID
from order
where customer id = #custID
and Total cashmovementValue
for current order id
is less than total (sold quantity * salePrice )
for current order id
How to do it?
Thanks.
You need to compare the sum of each order line with the sum of each payment per order. GROUP BY and a few sub-queries is what you need to get the job done.
Something like this should work:
SELECT
O.OrderID
FROM [Order] O
INNER JOIN (
-- Add up cost per order
SELECT
OrderID,
SUM(SoldQuantity * P.SalePrice) AS Total
FROM OrderLine
INNER JOIN Product P ON P.ProductID = OrderLine.ProductID
GROUP BY OrderID
) OL ON OL.OrderID = O.OrderID
LEFT JOIN (
-- Add up total amount paid per order
SELECT
OrderID,
SUM(CashMovementValue) AS Total
FROM CashMovement
GROUP BY OrderID
) C ON C.OrderID = O.OrderID
WHERE
O.CustomerID = #custID
AND ( C.OrderID IS NULL OR C.Total < OL.Total )
EDIT
I've just noticed you're not storing the sale price on each order line. I've updated my answer accordingly, but this is a very bad idea. What will happen to your old orders if the price of an item changes? It is okay (and actually best practice) to denormalise the data by storing the price at the time of sale on each order line.