How to get count of customer first time orders? - mysql

I have this query that needs to be corrected. So right now I have 90% of what I need but this last step has been giving me trouble. I know on 1996-07-04 employee #5 visited my site for the first time, and rightfully get the first timer count as 1. On 1996-07-11 I know employee #5 visited the site again but we do not want to count him again.
SELECT
Orders.OrderDate,
COUNT(OrderDetails.OrderDetailID) AS NumSessions,
COUNT(DISTINCT Orders.EmployeeID)
FROM OrderDetails
LEFT JOIN Orders
ON OrderDetails.OrderID=Orders.OrderID
GROUP BY Orders.OrderDate
EXPECTED:
DATE NumSessions FirstTimers
1996-07-04 3 1
1996-07-11 3 0
ACTUAL:
DATE NumSessions FirstTimers
1996-07-04 3 1
1996-07-11 3 1

Maybe something like this (I can't guarantee it's syntactically correct, though):
SELECT
Orders.OrderDate,
COUNT(OrderDetails.OrderDetailID) AS NumSessions,
COUNT(DISTINCT Orders.EmployeeID WHERE Orders.OrderDate = (
SELECT MIN(b.OrderDate) FROM Orders b WHERE Orders.EmployeeID = b.EmployeeID)
)
FROM OrderDetails
LEFT JOIN Orders
ON OrderDetails.OrderID=Orders.OrderID
GROUP BY Orders.OrderDate
But I don't know how this would do performance-wise. :)

This is a little complicated. One method is to use a subquery to calculate the first order date and to use that in the logic:
SELECT o.OrderDate,
COUNT(od.OrderDetailID) AS NumSessions,
SUM( o.OrderDate = oe.FirstOrderDate ) as FirstTimers
FROM Orders o LEFT JOIN
OrderDetails od
ON O.OrderId = od.OrderId LEFT JOIN
(SELECT o.EmloyeeID, MIN(OrderDate) as FirstOrderDate
FROM Orders o
GROUP BY OrderDate
) o
ON oe.EmployeeId = o.EmployeeId
GROUP BY o.OrderDate

Related

Finding first order in a single year

I'm trying to determine how many new people made an order in 2018. This looks straight forward enough but there is an error with putting calculated fields in the WHERE statement.
SELECT DISTINCT COUNT(c.customer_id)
FROM Customer c
LEFT JOIN
Orders o ON c.customer_id=o.customer_id
WHERE MIN(order_date) > '2017-12-31'
AND MIN(order_date) < '2019-01-01';
You can achieve this by putting a sequence number to the orders and then selecting the first row for each customer. Although, I'm not really sure why you're performing a count of the orders when you just want to consider the first orders. Nevertheless the below should work just fine.
SELECT count(res.customer_id) FROM (
SELECT c.customer_id,
ROW_NUMBER() OVER (PARTITION BY c.customer_id ORDER BY o.order_date ASC) row_num
FROM Customer c
LEFT JOIN Orders o ON c.customer_id=o.customer_id
WHERE o.order_date > '2017-12-31'
AND o.order_date < '2019-01-01'
) res WHERE res.row_num=1
Join with a subquery that finds the customers that were new in 2018.
SELECT COUNT(DISTINCT o.customer_id)
FROM Orders o
JOIN (
SELECT DISTINCT customer_id
FROM Orders
GROUP BY customer_id
HAVING MIN(order_date) > '2017-12-31'
) o1 ON o1.customer_id = o.customer_id
WHERE o.order_date < '2019-01-01';
There's also no need to join with Customers, since the customer ID is in Orders.
And the correct way to get the distinct count is COUNT(DISTINCT o.customer_id), not DISTINCT COUNT(o.customer_id).

How to write query to find commalities such as customers who ordered in same dates?

In a single table named orders with columns
OrderID CustomerID .. OrderDate ..
I am looking for pairs of customers who ordered in same dates and would like to generate a result set such as
CustomerID1 CustomerID2 NumberOfCommonDates
my best guess so far was this:
SELECT * FROM [Orders] AS a, [Orders] AS b
WHERE a.OrderDate = b.OrderDate AND a.CustomerID <> b.CustomerID
Any tips would be appreciated
You could self-join the table and use aggregation:
select
o1.CustomerID CustomerID1,
o2.CustomerID CustomerID2,
count(*) NumberOfCommonDates
from
orders o1
inner join orders o2
on o1.CustomerID < o2.CustomerID
and o1.OrderDate = o2.OrderDate
group by
o1.CustomerID,
o2.CustomerID
Join condition o1.CustomerID < o2.CustomerID ensures that you we not joining a record with itself, and also avoids duplicates in the result set like ('customerA', 'customerB') vs ('customerB', 'customerA').
Note: this assumes that column OrderDate is of DATE datatype. If it's a DATETIME, then you would need to extract the date part before comparing, like:
date(o1.OrderDate) = date(o2.OrderDate)
I am looking for pairs of customers who ordered in same dates and would like to generate a result set such as
CustomerID1 CustomerID2 NumberOfCommonDates
Based on this, you want a self-join and aggregation, similar to other answers. However, you need to be careful about customers who might make multiple orders on the same date.
The correct answer to that question is:
SELECT o1.CustomerID as CustomerID1,
o2.CustomerID as CustomerID2,
COUNT(DISTINCT o1.OrderDate) as NumberOfCommonDates
FROM Orders o1 JOIN
Orders o2
ON o1.OrderDate = o2.OrderDate AND
o1.CustomerID < o2.CustomerID
GROUP BY o1.CustomerID, o2.CustomerID
ORDER BY NumberOfCommonDates DESC;
The o1.CustomerID < o2.CustomerID is so the same pair of customers does not appear twice.
Based on the comments to other questions, I'm not sure this is what you really want. However, I figured that there should at least be a correct answer to the question you actually asked.
If this is not what you want, I would suggest that you ask a new question and provide sample data, desired results, and a clear explanation of what you want.
#Arzev Mansuri was on the right track. Slightly modified you can get your three columns. and even two more with a first and last common date:
SELECT o1.customer, o2.customer, Count(*) cnt, min(o1.pdate) dmin, case when count(*)>1 THEN max(o1.pdate) END dmax
FROM tbl o1
inner join tbl o2 on o1.pdate=o2.pdate and o1.customer<o2.customer
group by o1.customer, o2.customer
Sample output:
customer customer cnt dmin dmax
Ginny Hagrid 1 03.10.2019 00:00:00 NULL
Ginny Harry 1 07.10.2019 00:00:00 NULL
Ginny Hermiony 1 03.10.2019 00:00:00 NULL
Hagrid Hermiony 1 03.10.2019 00:00:00 NULL
Harry Ron 2 01.10.2019 00:00:00 01.10.2019 00:00:00
See demo here: https://rextester.com/DUGF43842
You can try with this
SELECT o1.customerid, o2.customerid, Count(*) as commonDates FROM Orders o1 join Orders o2 on o1.orderdate=o2.orderdate group by o1.customerid, o2.customerid
Is this what you want?
SELECT t.customerid, t1.customerid,
Count(distinct *) as numberofdates
FROM [Orders] t join Orders t1
on t.date=t1.date and t.customerid<>
t1.customerid group by customerid

select MAX(date) with associate value [duplicate]

This question already has answers here:
SQL select only rows with max value on a column [duplicate]
(27 answers)
Closed 6 years ago.
I have two tables. One is basic customer information and one is ordering information.
I'm trying to find the max(order date) with the order status of 'placed'or'cancelled'. I don't care if the status if placed or cancelled. I just want the most recent order.
The first table (Info)
CustomerID LAST NAME FIRST NAME
1 AB BOB
2 BC ROBERT
3 AA JOHN
The second table(order)
CustomerID Order Date Order Status
1 12/16/2016 placed
2 8/5/2016 cancelled
1 5/8/2015 cancelled
2 8/9/2016 placed
3 7/15/2016 cancelled
3 8/20/2015 placed
I want the result to be:
CustomerID FirstName LastName OrderDate OrderStatus
1 AB BOB 12/16/2016 placed
2 BA ROBERT 8/9/2016 placed
3 AA JOHN 7/15/2016 cancelled
Here are my SQL syntax
SELECT distinct Info.CustomerID, Info.Lastname,Info.Firstname
FROM INFO
INNER JOIN
(SELECT
order.CustomerID, LastOrderDate=max(OrderDate),order.OrderStatus
FROM Order
GROUP BY order.CustomerID, order.orderstatus)a
ON a.CustomerID=Info.CustomerID
This didn't work because it's grouping by order status which give me the max date of each all orderstatus. Then I tried
SELECT distinct Info.CustomerID, Info.Lastname,Info.Firstname, Order.OrderStatus
FROM INFO, Order
INNER JOIN
(SELECT
order.CustomerID, LastOrderDate=max(OrderDate)
FROM Order
GROUP BY order.CustomerID)a
ON a.CustomerID=Info.CustomerID
This didn't work either because it says the Info.CustomerID could not be bound.
Any helps? Thanks!
Can you try the following query:
SELECT c.customerid, c.last_name, c.first_name, o.order_status, MAX(order_date)
FROM customer c JOIN order ON c.customerid = o.customerid
WHERE o.order_status IN ('placed', 'cancelled')
GROUP BY c.customerid, c.last_name, c.first_name, o.order_status;
update
If you don't want the max date by order status then you can remove it from group by, e.g.:
SELECT c.customerid, c.last_name, c.first_name, MAX(order_date)
FROM customer c JOIN order ON c.customerid = o.customerid
WHERE o.order_status IN ('placed', 'cancelled')
GROUP BY c.customerid, c.last_name, c.first_name;
Another update
Following query would return both the records if an order gets placed and cancelled on the same day:
SELECT c.customerid, c.first_name, c.last_name, o.order_date, o.order_status
FROM customer c JOIN
(SELECT o1.customerid, o1.order_date, o1.order_status
FROM `order` o1 JOIN
(SELECT o.customerid, max(o.order_date) as max_date
FROM `order` o
WHERE o.order_status in ('placed', 'cancelled')
GROUP BY o.customerid) o2
ON o1.customerid = o2.customerid and o1.order_date = o2.max_date) o
ON c.customerid = o.customerid;
Here's the SQL Fiddle.

MySql query to select total orders for customers

There title does not quite describe well what i need from the query.
#sgeddes helped me come up with the following query but the query needs some alteration to accomplish my needs. I also modified the query slightly to not Select deleted customers but i couldn't change much due to the way this query is written is out my SQL knowledge.
SELECT d.customer_id,d.fname,d.lname,d.isactive,
o.lastdate,
Count(o2.order_id) AS 'total_orders'
FROM customers d
LEFT JOIN (SELECT MAX(order_id) order_id, customer_id
FROM orders
GROUP BY customer_id) m on d.customer_id = m.customer_id
LEFT JOIN orders o on m.order_id = o.order_id
LEFT JOIN orders o2 on d.customer_id = o2.customer_id
AND o2.balance > 0 AND o2.isActive > -1
WHERE d.user_id =945766 AND d.isActive > -1
AND o2.customer_id IS NULL
GROUP BY d.customer_id
I need the three following requirements.
count orders for customer with isActive > -1 (-1 = deleted)
Customers not in orders table (customer with no orders).
Customers with isActive = 0 and their corresponding order count
so briefly all I need is customer with isActive = 0 and to get an actual # for total_orders column.
In my attempt to better help you understand my requirement I created a SqlFiddle.
Please see my SqlFiddle
If your requirement is what you mentioned in your 3 points then you can use below queries-
If you want separate query then use below-
SELECT d.customer_id, d.fname, COUNT(o.order_id) AS Total_Orders
FROM customer d
LEFT JOIN orders o ON d.customer_id=o.customer_id
WHERE d.isActive > -1
GROUP BY d.customer_id;
SELECT DISTINCT d.customer_id, d.fname
FROM customer d
LEFT JOIN orders o ON d.customer_id=o.customer_id
WHERE o.customer_id IS NULL;
SELECT d.customer_id, d.fname, COUNT(o.order_id) AS Total_Orders
FROM customer d
LEFT JOIN orders o ON d.customer_id=o.customer_id
WHERE d.isActive = 0
GROUP BY d.customer_id;
If you want to merge them by union then use below-
SELECT 'isactive>-1' AS 'status', d.customer_id, d.fname, COUNT(o.order_id) AS Total_Orders
FROM customer d
LEFT JOIN orders o ON d.customer_id=o.customer_id
WHERE d.isActive > -1
GROUP BY d.customer_id
UNION ALL
SELECT DISTINCT 'Customer without Order' AS 'status', d.customer_id, d.fname, COUNT(o.order_id) AS Total_Orders
FROM customer d
LEFT JOIN orders o ON d.customer_id=o.customer_id
WHERE o.customer_id IS NULL
UNION ALL
SELECT 'isactive=0' AS 'status', d.customer_id, d.fname, COUNT(o.order_id) AS Total_Orders
FROM customer d
LEFT JOIN orders o ON d.customer_id=o.customer_id
WHERE d.isActive = 0
GROUP BY d.customer_id;
Note: Your main query is trying fetch latest order which can be for any other purpose, so if you provide your exact requirement if different from it then someone can help you.

Can I execute a COUNT() before GROUP BY

I am working on an mySQL assignment for school and I am stuck on a question. I am still new to mySQL. COUNT(o.customer_id) is not working the way I want. I want it to count the number of orders but it is counting all items. i.e. Customer 1 has 2 orders but it is returning 3 because one order has two items. I have three tables one with customers, another with orders than another with each item on each order. Ive posed my query below. Any help would be great.
SELECT email_address, COUNT(o.order_id) AS num_of_orders,
SUM(((item_price - discount_amount) * quantity)) AS total
FROM customers c JOIN orders o
ON c.customer_id = o.customer_id
JOIN order_items ot
ON o.order_id = ot.order_id
GROUP BY o.customer_id
HAVING num_of_orders > 1
ORDER BY total DESC;
As simple as use Distinct reserved word:
SELECT email_address, COUNT(distinct o.order_id) AS num_of_orders
Looks like you want to count the DISTINCT number of orders. Add a DISTINCT into the COUNT. Although MySQL allows you to use the SELECT expression in the HAVING clause, it's not good practice to do so.
SELECT email_address, COUNT(DISTINCT o.order_id) AS num_of_orders,
SUM(((item_price - discount_amount) * quantity)) AS total
FROM customers c JOIN orders o
ON c.customer_id = o.customer_id
JOIN order_items ot
ON o.order_id = ot.order_id
GROUP BY o.customer_id
HAVING COUNT(DISTINCT o.order_id) > 1
ORDER BY total DESC;
Just take out the join to items. All it is doing is duplicating rows when there are multiple items.
SELECT email_address, COUNT(o.order_id) AS num_of_orders,
SUM(((item_price - discount_amount) * quantity)) AS total
FROM customers c JOIN orders o
ON c.customer_id = o.customer_id
GROUP BY o.customer_id
HAVING COUNT(o.order_id) > 1
ORDER BY total DESC;