I want to find the best selling products according to this criteria.
Minimum order = 5
Product A = 100 orders -last order = 29 Dec 2021
Product B = 6 orders - last order = 1 Jan 2022
Product C = 3 Orders - last order = 3 Jan 2022
Product B must show first.
Product C will not show because it has less than 5 orders.
Here is my database structure and what I tried
http://sqlfiddle.com/#!9/04e2a92/23
Here's the query for getting all products with minimum order count of 5, sorted in descending order.
SELECT p_name,
tmp.total_orders,
tmp.last_purchased
FROM products P
INNER JOIN (
SELECT product_id,
COUNT(*) AS total_orders,
MAX(created_at) AS last_purchased
FROM order_items
GROUP BY product_id
HAVING total_orders >= 5
) AS tmp ON tmp.product_id = P.id
ORDER BY last_purchased DESC
We ran a promotion where users can receive their first subscription order free. Price = $0.00 when a user uses the promo. I am interested in the data from Example A.
Example A - User 50 started with the promo and continued for two months
order_id user_id price created_at
1 50 0.00 2018-01-15
5 50 20.00 2018-02-15
9 50 20.00 2018-03-15
Example B - User 100 was already an active subscriber who cancelled his account and reactivated with the promo, I do not wish to count him
order_id user_id price created_at
2 100 20.00 2018-01-16
3 100 0.00 2018-01-17
7 100 20.00 2018-02-17
--Here is my query--
This returns all users who have multiple orders
WHERE at least one of their orders has a price = 0.00
-This dataset returns example A and example B
--My question--
Most of this data is correct (Example A) but a handful of them I want to omit because they are skewing my data (Example B). I want to remove Example B users.
I want to remove people who's first order was not the promo.
How can I request that their FIRST order had a price = 0.00? I was thinking something with min(created_at)?
You can get the time of the first order using:
select user_id, min(created_at) as min_ca
from t
group by user_id;
Next, you can get the price of the first order using:
select oi.*
from order_items oi join
(select user_id, min(created_at) as min_ca
from order_items oi
group by user_id
) ooi
on oi.user_id = ooi.user_id and oi.created_at = ooi.min_ca
where oi.price = 0.00;
Then you can get all records, using join, in, or exists;
select oi.*
from order_items oi join
order_items oi1
on oi.user_id = oi1.user_id join
(select user_id, min(created_at) as min_ca
from order_items oi
group by user_id
) u1
on oi1.user_id = u1.user_id and oi1.created_at = u1.min_ca
where oi1.price = 0.00;
You can use EXISTS to check that for the record with zero price there is no earlier created_at:
SELECT COUNT(*), user_id
FROM Promo
WHERE user_id IN (
-- Query below yields [user_id]s of users who got the promo
-- that wasn't a result of a cancellation and re-activation
SELECT user_id
FROM Promo p
WHERE p.price = 0 AND NOT EXISTS (
-- Look for a record with the same user ID and an earlier date
-- than p.created_at, which is the date of the promo with 0.00 price
SELECT *
FROM Promo pp
WHERE pp.user_id=p.user_id AND pp.created_at < p.created_at
)
)
GROUP BY user_id
Maybe my google fu is off.
I have a table: sub_transfer_jobs
job_date mo_id sub_quantity shift_id
2017-05-16 24581 12 1
2017-05-16 86122 8 2
etc.
Another table: mo_numbers
mo_id customer
24581 cust1
86122 cust2
68515 cust1
etc.
I have another table: Calendar.
This just has a date value for every date
What i need to get is a string list of amounts per day per customer
example
2017-05-15 cust1 50
2017-05-15 cust2 0
2017-05-16 cust1 22
2017-05-16 cust2 10
etc
I was going to get a distinct list of customers based one what customers are seen based on a date range
This is where i am but have a problem on the sub query
SELECT `sub_transfer_jobs`.`sub_quantity`, `sub_transfer_jobs`.`job_date`, `sub_transfer_jobs`.`shift_id`, `mo_numbers`.`customer`
FROM `sub_transfer_jobs`
join mo_numbers on `mo_numbers`.`mo_id` = `sub_transfer_jobs`.`mo_id`
right join calendar on `calendar`.`datefield` = `sub_transfer_jobs`.`job_date`
right join (
select DISTINCT `mo_numbers`.`customer` from sub_transfer_jobs
join `mo_numbers` on `mo_numbers`.`mo_id` = `sub_transfer_jobs`.`mo_id`
where job_date > '2017-04-15'
) as customerList on customerList.customer = mo_numbers.customer
where job_date > '2017-04-15'
group by `mo_numbers`.`customer`, `sub_transfer_jobs`.`job_date`
EDIT: Correct sql to get what I needed (grouped for comma seperated)
select basecustomer, GROUP_CONCAT(IFNULL(customerdaytotals.total, 0) ORDER BY datefield ASC) AS total FROM
(select basecustomer, datefield from
(select distinct `mo_numbers`.`customer` as basecustomer
FROM `sub_transfer_jobs`
JOIN `mo_numbers` on `mo_numbers`.`mo_id` = `sub_transfer_jobs`.`mo_id`
where `sub_transfer_jobs`.`job_date` > '2017-04-01') as used_customers
CROSS JOIN (
SELECT `calendar`.`datefield` from `calendar`
WHERE `calendar`.`datefield` > '2017-04-01' AND `calendar`.`datefield` < '2017-05-11'
) as daterange) as basedata
LEFT JOIN (
select `sub_transfer_jobs`.`job_date`, `mo_numbers`.`customer`, sum(`sub_transfer_jobs`.`sub_quantity`) as total
FROM `sub_transfer_jobs`
JOIN `mo_numbers` on `mo_numbers`.`mo_id` = `sub_transfer_jobs`.`mo_id`
GROUP BY `sub_transfer_jobs`.`job_date`, `mo_numbers`.`customer`
) as customerdaytotals on customerdaytotals.job_date = basedata.datefield and customerdaytotals.customer = basedata.basecustomer
GROUP BY basecustomer
Which gives my result of
cust1 0,1857,1262,1166,517,1551,0,0,1469,1670,400,0,0,0,...
cust2 0,123,7,0,7,0,0,0,0,0,0,0,0,0,0,84,70,9,53,3,0,0,4...
cust3 0,0,75,425,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0...
cust4 0,0,41,36,44,26,0,0,0,41,0,0,0,0,0,16,88,12,0,0,0,...
cust5 0,277,552,433,280,491,0,0,124,880,1269,0,0,0,0,495...
cust6 0,255,124,620,184,129,0,0,309,103,88,0,0,0,0,118,2...
cust7 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,...
cust8 0,209,123,15,84,296,0,0,296,15,262,0,0,0,0,301,200,...
You need to use CROSS JOIN to get all combinations of customers and dates. Then LEFT JOIN that with a query that gets each customer's total for each date.
SELECT m.date, c.customer, IFNULL(t.total, 0) AS total
FROM mo_numbers AS m
CROSS JOIN customer AS c
LEFT JOIN (
SELECT date, mo_id, SUM(quantity) AS total
FROM mo_numbers
GROUP BY date, mo_id
) AS t ON m.mo_id = t.mo_id AND c.mo_id = t.mo_id
I'm trying to find out if a user who used a discount code has ordered after the initial order.
The three tables are: order, user, coupon_uses
From coupon_uses, the only data I'm retrieving is users who used code via:
SELECT *
FROM coupon_uses
WHERE coupon_id = 21921
I would get a return a table with the user ID, order ID, and Coupon they used.
ID Coupon_ID User_ID Order_ID
11 21921 148871 1448181
21 21921 888381 1448191
31 21921 888411 1448201
41 21921 354311 1448211
51 21921 452671 1448221
61 21921 684791 1448231
Now, I need to check the users that are returned in the first query (who used the code) verses the entire order table:
I tried something like this:
SELECT order.user_id,
COUNT(*) AS Total_Orders
FROM `order`
WHERE `order`.user_id = (
SELECT user_id
FROM coupon_uses
WHERE coupon_id = 21921)
AND order.order_status != "Cancelled"
GROUP BY order.user_id ASC
ORDER BY `order`.orderplaced_ts
But I receive Subquery returns more than 1 row.
The desired result would be return a list of user IDs, with the total orders they placed and the date of of the order.
User_ID Total_Orders Last_Order
148871 17 2015_01_01
888381 19 2015_01_01
888411 3 2015_01_14
354311 5 2015_05_01
452671 99 2015_02_01
684791 213 2015_01_05
Thanks.
Try this:
SELECT o.user_id, COUNT(*) AS total_orders
FROM order AS o
INNER JOIN coupon_uses AS c ON o.user_id = c.user_id
WHERE c.coupon_id = 21921
GROUP BY o.user_id
ORDER BY MIN(o.orderplaced_ts)
This assumes that a user can only use a coupon once.
I have a spendings table and a dates table, that are joined by date_id and id...
What I'm trying to do, is get from 1 query all the info from spendings, plus the sum of all the spendings but with a limit and/or offset
This is the query right now
SELECT spendings.id, spendings.price, spendings.title,
dates.date, users.username, currencies.value,
( SELECT SUM(sum_table.price)
FROM (
SELECT s.price
FROM spendings s, dates d
WHERE s.date_id = d.id
AND day(d.date) = 25
LIMIT 2 OFFSET 0
) as sum_table
) AS sum_price
FROM spendings, dates, users, currencies
WHERE spendings.date_id = dates.id
AND day(dates.date) = 25
AND spendings.user_id = users.id
AND spendings.curr_id = currencies.id
LIMIT 2 OFFSET 0
Output
id price title date username value sum_price
3 6.00 title1 2013-11-25 alex € 21.00
4 15.00 title2 2013-11-25 alex € 21.00
It works, but only if the date here day(d.date) = 25 is the same as the outer one here day(dates.date) = 25
If instead I put day(d.date) = day(dates.date) which seems the logic thing to do, I get #1054 - Unknown column 'dates.date' in 'where clause'
If anyone has an idea to make this simpler let me know :)
Try to join instead of using nested correlated subqueries:
SELECT spendings.id, spendings.price, spendings.title,
dates.date, users.username, currencies.value,
y.sum_price
FROM spendings, dates, users, currencies
JOIN (
SELECT day, SUM(sum_table.price) As sum_price
FROM (
SELECT day(d.date) As day,
s.price
FROM spendings s, dates d
WHERE s.date_id = d.id
AND day(d.date) = 25
LIMIT 2 OFFSET 0
) sum_table
GROUP BY day
) y
ON y.day = day(dates.date)
WHERE spendings.date_id = dates.id
-- AND day(dates.date) = 25 <== commented since it's redundant now
AND spendings.user_id = users.id
AND spendings.curr_id = currencies.id
Some remarks:
Using old join syntax with commas is not recommended: FROM table1,table2,table2 WHERE
The recommended way of expressing joins is "new" ANSI SQL join syntax:
FROM table1
[left|right|cross|[full] outer|natural] JOIN table2 {ON|USING} join_condition1
[left|right|cross|[full] outer|natural] JOIN table3 {ON|USING} join_condition2
....
Actually this "new syntax" is quite old now, since is has been published, as I remember, in 1992 - 22 years ago. In IT industry 22 years is like 22 ages.