I am trying to identify shoppers who last placed an order on or before a specific date.
I want to do this so that I can identify stale accounts and unsubscribe them from mailings.
So far I have this query, but it seems to be retrieving accounts that have ordered more recently than the specified date - which is not what I want!
SELECT
s.id,s.first_name,s.last_name,s.email, latest_orders.last_order_date, au.verified, au.unh
FROM
(SELECT
shopper_id, MAX(order_date) AS last_order_date
FROM
order_list WHERE order_date <= ?
GROUP BY
shopper_id) AS latest_orders
INNER JOIN
shoppers s
ON
s.id = latest_orders.shopper_id
JOIN auth_users au ON au.shopper_id=s.id
WHERE s.mail_outs='Y' LIMIT 50
Use having:
SELECT shopper_id, MAX(order_date) AS last_order_date
FROM order_list
GROUP BY shopper_id
HAVING MAX(order_date) <= ?;
If you want all information about the shoppers, then join back to shoppers:
SELECT s.*, os.last_order_date
FROM shoppers s JOIN
(SELECT shopper_id, MAX(order_date) AS last_order_date
FROM order_list
GROUP BY shopper_id
HAVING MAX(order_date) <= ?
) os
ON os.shopper_id = s.id;
Related
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).
Here's my orders table:
I want to select all orders excluding very first order of each customer (if customer has placed multiple orders).
So if a customer e.g. 215 has total 8 orders, then I will select his all last 7 orders excluding his very first order 70000 which was placed on 10 July 2017.
But if a customer e.g. 219 had placed only one order 70007, it must be selected by the query.
Using an anti-join approach:
SELECT o1.order_id, o1.customer_id, o1.order_date, o1.order_value
FROM orders o1
LEFT JOIN
(
SELECT customer_id, MIN(order_date) AS min_order_date, COUNT(*) AS cnt
FROM orders
GROUP BY customer_id
) o2
ON o1.customer_id = o2.customer_id AND
o1.order_date = o2.min_order_date
WHERE
o2.customer_site = 1 AND
(o2.customer_id IS NULL OR
o2.cnt = 1);
The idea here is to try to match each record in orders to a record in the subquery, which contains only first order records, for each customer. If we can't find a match, then such an order record cannot be the first.
You can try below -
select order_id,customer_id,order_date,order_Value
from tablename
group by order_id,customer_id,order_date,order_Value
having count(order_id)=1
union all
select order_id,customer_id,order_date,order_Value
from tablename a where order_date not in (select min(order_date) from tablename b
where a.customer_id=b.customer_id)
Solution
Dear #Tim Biegeleisen, your answer almost done. just add HAVING COUNT(customer_id)>1
So the query is below:
SELECT o1.order_id, o1.customer_id, o1.order_date, o1.order_value
FROM orders o1
LEFT JOIN (
SELECT customer_id, MIN(order_date) AS min_order_date
FROM orders
GROUP BY customer_id
HAVING COUNT(customer_id)>1
) o2
ON o1.customer_id = o2.customer_id AND
o1.order_date = o2.min_order_date
WHERE
o2.customer_id IS NULL;
I have 3 tables: users, orders and order_prices with the latter containing the analysis of each order and I need to find the customers that re-ordered in a specific month, ( both tables have user_id, order_id, order_date, good_id(only order_prices) etc) my script is the following:
select o.system_id, o.user_id, o.date, o.id
from orders o
where o.date >= '2018-11-01' and o.date <= '2018-11-30' -- in the date range
AND o.user_id in
( -- has made the same order (content)
select op.user_id
from order_prices op join users u on u.id = op.user_id
where op.good_id in
(
select good_id
from order_prices
where user_id = o.user_id
)
And u.number_of_orders > 0 -- has ordered before
)
group by o.user_id
Well i am not sure if this even works logically, also I guess I need to find those users that their previous order was the same in content with their last order the above script doesn't take into consideration.... any suggestions MORE than welcome!
I try to obtain a list of all customers my company has not had any assignments for in the last year.
SELECT MAX(assignment_date), full_name
FROM assignments
CROSS JOIN customers
WHERE assignments.customer_id = customers.id
AND assignment_date < '2017-01-01' -- Dynamic value from backend
GROUP BY full_name
ORDER BY assignment_date DESC
This does not seem to work as intended however, since it only returns some customers we did have assignments for in that timeframe. How would I go about implementing such a feature?
Try this code:
SELECT MAX(assignment_date), full_name
FROM customers
where id not in (SELECT id FROM customers inner join assigments on customers.id = assignments.customer_id WHERE assignment_date > '2017-01-01' )
This will return all customers in your database and remove all of them who did have assigments in last year. You should get all customers without assigments before '2017-01-01' as a result
left join customers to assignments where assignments.customer_id IS NULL
and assignment_date greater than '2017-01-01' i.e.
SELECT MAX(assignment_date), full_name
FROM assignments
WHERE assignments.customer_id IN
(SELECT customers.id
FROM customers
LEFT JOIN assignments ON assignments.customer_id = customers.id
WHERE assignments.customer_id IS NULL
AND assignment_date > '2017-01-01')
GROUP BY full_name
ORDER BY assignment_date DESC
I would suggest left join, group by and having:
SELECT MAX(assignment_date), full_name
FROM customers c LEFT JOIN
assignments a
ON a.customer_id = c.id
GROUP BY c.full_name
HAVING MAX(a.assignment_date) < '2017-01-01' OR
MAX(a.assignment_date) IS NULL
ORDER BY MAX(assignment_date) DESC;
It seems you want to show all customers with their last assignment date, but you want to restrict that list to customers that had no assignment since 2017-01-01. This means the dates you will be showing will be null for those customers who had never had an assignment and a date before 2017-01-01 for the others.
So outer join the last dates to the customers and only keep the rows where that date is before 2017-01-01 or null:
select c.full_name, a.max_date
from customers c
left join
(
select customer_id, max(assignment_date) as max_date
from assignments
group by customer_id
) a on a.customer_id = c.customer_id
where a.max_date < date '2017-01-01'
or a.max_date is null
order by a.max_date desc;
I am having to set up a query that retrieves the last comment made on a customer, if no one has commented on them for more than 4 weeks. I can make it work using the query below, but for some reason the comment column won't display the latest record. Instead it displays the oldest, however the date shows the newest. It may just be because I'm a noob at SQL, but what exactly am I doing wrong here?
SELECT DISTINCT
customerid, id, customername, user, MAX(date) AS 'maxdate', comment
FROM comments
WHERE customerid IN
(SELECT DISTINCT id FROM customers WHERE pastdue='1' AND hubarea='1')
AND customerid NOT IN
(SELECT DISTINCT customerid FROM comments WHERE DATEDIFF(NOW(), date) <= 27)
GROUP BY customerid
ORDER BY maxdate
The first "WHERE" clause is just ensuring that it shows only customers from a specific area, and that they are "past due enabled". The second makes sure that the customer has not been commented on within the last 27 days. It's grouped by customerid, because that is the number that is associated with each individual customer. When I get the results, everything is right except for the comment column...any ideas?
Join much better to nested query so you use the join instead of nested query
Join increase your speed
this query resolve your problem.
SELECT DISTINCT
customerid,id, customername, user, MAX(date) AS 'maxdate', comment
FROM comments inner join customers on comments.customerid = customers.id
WHERE comments.pastdue='1' AND comments.hubarea='1' AND DATEDIFF(NOW(), comments.date) <= 27
GROUP BY customerid
ORDER BY maxdate
I think this might probably do what you are trying to achieve. If you can execute it and maybe report back if it does or not, i can probably tweak it if needed. Logically, it ' should' work - IF i have understood ur problem correctly :)
SELECT X.customerid, X.maxdate, co.id, c.customername, co.user, co.comment
FROM
(SELECT customerid, MAX(date) AS 'maxdate'
FROM comments cm
INNER JOIN customers cu ON cu.id = cm.customerid
WHERE cu.pastdue='1'
AND cu.hubarea='1'
AND DATEDIFF(NOW(), cm.date) <= 27)
GROUP BY customerid) X
INNER JOIN comments co ON X.customerid = co.customerid and X.maxdate = co.date
INNER JOIN customer c ON X.customerid = c.id
ORDER BY X.maxdate
You need to have subquery for each case.
SELECT a.*
FROM comments a
INNER JOIN
(
SELECT customerID, max(`date`) maxDate
FROM comments
GROUP BY customerID
) b ON a.customerID = b.customerID AND
a.`date` = b.maxDate
INNER JOIN
(
SELECT DISTINCT ID
FROM customers
WHERE pastdue = 1 AND hubarea = 1
) c ON c.ID = a.customerID
LEFT JOIN
(
SELECT DISTINCT customerid
FROM comments
WHERE DATEDIFF(NOW(), date) <= 27
) d ON a.customerID = d.customerID
WHERE d.customerID IS NULL
The first join gets the latest record for each customer.
The second join shows only customers from a specific area, and that they are "past due enabled".
The third join, which uses LEFT JOIN, select all customers that has not been commented on within the last 27 days. In this case,only records without on the list are selected because of the condition d.customerID IS NULL.
But tomake your query shorter, if the customers table has already unique records for customer, then you don't need to have subquery on it.Directly join the table and put the condition on the WHERE clause.
SELECT a.*
FROM comments a
INNER JOIN
(
SELECT customerID, max(`date`) maxDate
FROM comments
GROUP BY customerID
) b ON a.customerID = b.customerID AND
a.`date` = b.maxDate
INNER JOIN customers c
ON c.ID = a.customerID
LEFT JOIN
(
SELECT DISTINCT customerid
FROM comments
WHERE DATEDIFF(NOW(), date) <= 27
) d ON a.customerID = d.customerID
WHERE d.customerID IS NULL AND
c.pastdue = 1 AND
c.hubarea = 1
Two of your table columns are not contained in either an aggregate function or the GROUP BY clause. for example suppose that you have two data rows with the same customer id and same date, but with different comment data. how SQL should aggregate these two rows? :( it will generate an error...
try this
select customerid, id, customername, user,date, comment from(
select customerid, id, customername, user,date, comment,
#rank := IF(#current_customer = id, #rank+ 1, 1),
#current_customer := id
from comments
where customerid IN
(SELECT DISTINCT id FROM customers WHERE pastdue='1' AND hubarea='1')
AND customerid NOT IN
(SELECT DISTINCT customerid FROM comments WHERE DATEDIFF(NOW(), date) <= 27)
order by customerid, maxdate desc
) where rank <= 1