I have 3 columns(customerid, date_purchased, item) table with 2 weeks of data. I want to retrieve the customers that only bought from the first week. My logic is to find the max date subtract it all the rest of the dates and retrieve customers where that difference equal or less than 7. Here is what I did, but I have a problem with my query.
select distinct(customerid) from customer where datediff(max(date_purchased),Orderdate)<=7;
You could filter with a correlated subquery:
select distinct customerid
from customer
where date_purchased > (
select max(date_purchased) - interval 7 day from customer
)
You can first group by max() date_purchased per customer id then join it to get orderdate less than 7 days from your date of purchase.
select distinct(customerid)
from customer t1
inner join
(select max(date_purchased) date_purchased, customerid as date_purchased
from customer group by customerid) t2
on t2.customerid = t1.customerid
where datediff(t2.date_purchased, t1.Orderdate) <= 7
You can do this with aggregation, if you prefer:
select customerid
from customer
group by customerid
having max(date_purchased) > max(max(datepurchased)) over () - interval 7 day;
Related
I'm having great difficulty writing this query and cannot find any answers online which could be applied to my problem.
I have a couple of tables which looks similar to the below with. Each purchase date corresponds with an item purchased.
Cust_ID
Purchase_Date
123
08/01/2022
123
08/20/2022
123
09/05/2022
123
10/08/2022
123
12/25/2022
123
01/26/2023
The result I am looking for should contain the customers ID, a range of the purchases, the number of consecutive months they had made a purchase (regardless of which day they purchased), and a count of how many purchases they had made in the time frame. The result should look something like the below for my example.
Cust_ID
Min Purchase Date
Max Purchase Date
Consecutive Months
No. Items Purchased
123
08/01/2022
10/08/2022
3
4
123
12/25/2022
01/26/2023
2
2
I have tried using CTEs with querys similar to
WITH CTE as
(
SELECT
PaymentDate PD,
CustomerID CustID,
DATEADD(m, -ROW_NUMBER() OVER (PARTITION BY c.CustomerID ORDER BY
DATEPART(m,PaymentDate)), PaymentDate) as TempCol1,
FROM customers as c
LEFT JOIN payments as p on c.customerid = p.customerid
GROUP BY c.CustomerID, p.PaymentDate
)
SELECT
CustID,
MIN(PD) AS MinPaymentDate,
MAX(PD) AS MaxPaymentDate,
COUNT(*) as ConsecutiveMonths,
FROM CTE
GROUP BY CustID, TempCol1
However, the above failed to properly count consecutive months. When the payment dates matched a month apart (e.g. 1/1/22 - 2/1/22), the query properly counts the consecutive months. However, if the dates do not match from month to month (e.g. 1/5/22 - 2/15/22), the count breaks.
Any guidance/help would be much appreciated!
This is just a small enhancement on the answer already given by ahmed. If your date range for this query is more than a year, then year(M.Purchase_Date) + month(M.Purchase_Date) will be 2024 for both 2022-02-01 and 2023-01-01 as YEAR() and MONTH() both return integer values. This will return incorrect count of consecutive months. You can change this to use CONCAT() or FORMAT(). Also, the COUNT(*) for ItemsPurchased should be counting the right hand side of the join, as it is a LEFT JOIN.
WITH consecutive_months AS
(
SELECT *,
DATEADD(
month,
-DENSE_RANK() OVER (
PARTITION BY CustomerID
ORDER BY YEAR(PaymentDate), MONTH(PaymentDate)
),
PaymentDate
) AS grp_date
FROM payments
)
SELECT
C.CustomerID AS CustID,
MIN(M.PaymentDate) AS MinPaymentDate,
MAX(M.PaymentDate) AS MaxPaymentDate,
COUNT(DISTINCT FORMAT(M.PaymentDate, 'yyyyMM')) AS ConsecutiveMonths,
COUNT(M.CustomerID) AS ItemsPurchased
FROM customers C
LEFT JOIN consecutive_months M
ON C.CustomerID = M.CustomerID
GROUP BY C.CustomerID, YEAR(M.grp_date), MONTH(M.grp_date)
Here's a db<>fiddle
You need to use the dense_rank function instead of the row_number, this will give the same rank for the same months and avoid breaking the grouping column. Also, you need to aggregate for 'year-month' of the grouping date column.
with consecutive_months as
(
select *,
Purchase_Date - interval
dense_rank() over (partition by Cust_ID order by year(Purchase_Date), month(Purchase_Date))
month as grp_date
from payments
)
select C.Cust_ID,
min(M.Purchase_Date) as MinPurchaseDate,
max(M.Purchase_Date) as MaxPurchaseDate,
count(distinct year(M.Purchase_Date), month(M.Purchase_Date)) as ConsecutiveMonthsNo,
count(M.Cust_ID) as ItemsPurchased
from customers C left join consecutive_months M
on C.Cust_ID = M.Cust_ID
group by C.Cust_ID, year(M.grp_date), month(M.grp_date)
See demo on MySQL
You tagged your question with MySQL, while it seems that you posted an SQL Server query syntax, for SQL Server just use dateadd(month, -dense_rank() over (partition by Cust_ID order by year(Purchase_Date), month(Purchase_Date)), Purchase_Date).
See demo on SQL Server.
I have table with fields Customer date and amount
I want to sum Amount grouped by customer except the last two amounts of every customer by date
sample data
customer date amount
a 2020-10-1 100
a 2020-10-2 150
a 2020-10-3 30
a 2020-10-4 20
b 2020-10-1 1
b 2020-10-5 13
b 2020-10-7 50
b 2020-10-9 18
desired result
Customer Amount
A 150
B 14
something like
select Customer ,
SUM(amount- last 2 amount)
From TableA
Group By Customer
One option uses window functions, available in MySQL 8.0:
select customer, sum(amount) total_amount
from (
select a.*, row_number() over(partition by customer order by date desc) rn
from tablea a
) a
where rn > 2
group by customer
In earlier versions, an alternative uses a correlated subquery that returns the third latest date per customer for filtering:
select customer, sum(amount) total_amount
from tablea a
where date <= (select a1.date from tablea a1 where a1.customer = a.customer order by a1.date desc limit 2, 1)
group by customer
I have 2 tables
1st: order
columns: id, date, price
2nd: paypal
columns: id, posted_date, amount
the columns date and posted_date contains the full date & time details; day/month/year hrs:minute:seconds
I need to get the data by grouping by the day from the both tables
order.date (day by day)
count all orders from order table for each day
sum of all price records from order table for each day
sum of all amount records from the another table paypal table for the same days
I can't imagine if I should use join, union, union all, or just merge by comma
SELECT DATE(O.`dater`) AS Dates,
COUNT(O.orders) AS Order_count,
SUM(O.price) as Total_Price,
(SELECT SUM(amount) FROM paypal WHERE DATE(O.`dater`)=`posted_date`) AS Total_Amount
FROM orders O
GROUP BY DATE(O.`dater`)
Note:(I have used column dater instead of column date)
Hope this helps.
This one working for me :)
SELECT DATE(O.`date`) AS Dates,
COUNT(O.order) AS Order_count,
SUM(O.price) as Total_Price,
(SELECT SUM(amount) FROM paypal WHERE DATE(O.`date`)=`posted_date`) AS Total_Amount
FROM order O
GROUP BY DATE(O.`date`)
I have a table with prices and dates on product:
id
product
price
date
I create a new record when price change. And I have a table like this:
id product price date
1 1 10 2014-01-01
2 1 20 2014-02-17
3 1 5 2014-03-28
4 2 25 2014-01-05
5 2 12 2014-02-08
6 2 30 2014-03-12
I want to get last price for all products. But when I group with "product", I can't get a price from a row with maximum date.
I can use MAX(), MIN() or COUNT() function in request, but I need a result based on other value.
I want something like this in final:
product price date
1 5 2014-03-28
2 30 2014-03-12
But I don't know how. May be like this:
SELECT product, {price with max date}, {max date}
FROM table
GROUP BY product
Alternatively, you can have subquery to get the latest get for every product and join the result on the table itself to get the other columns.
SELECT a.*
FROM tableName a
INNER JOIN
(
SELECT product, MAX(date) mxdate
FROM tableName
GROUP BY product
) b ON a.product = b.product
AND a.date = b.mxdate
I think the easiest way is a substring_index()/group_concat() trick:
SELECT product,
substring_index(group_concat(price order by date desc), ',', 1) as PriceOnMaxDate
max(date)
FROM table
GROUP BY product;
Another way, that might be more efficient than a group by is:
select p.*
from table t
where not exists (select 1
from table t2
where t2.product = t.product and
t2.date > t.date
);
This says: "Get me all rows from the table where the same product does not have a larger date." That is a fancy way of saying "get me the row with the maximum date for each product."
Note that there is a subtle difference: the second form will return all rows that on the maximum date, if there are duplicates.
Also, for performance an index on table(product, date) is recommended.
You can use a subquery that groups by product and return the maximum date for every product, and join this subquery back to the products table:
SELECT
p.product,
p.price,
p.date
FROM
products p INNER JOIN (
SELECT
product,
MAX(date) AS max_date
FROM
products
GROUP BY
product) m
ON p.product = m.product AND p.date = m.max_date
SELECT
product,
price,
date
FROM
(SELECT
product,
price,
date
FROM table_name ORDER BY date DESC) AS t1
GROUP BY product;
How do I write a query to display the cust_id and cust_name_last for each customer who had orders in two successive months in the current year. (successive meaning they follow each other 'may, june')
for example: customer 3 has orders in May and June of this year.
select cust_id, cust_name_last
from customer
where date_sub (order_date, interval 1 month)
and date_sub (order_date, interval 2 months)
"I just want to know how to find customers with orders in consecutive months in a year"
Could you try this?
SELECT DISTINCT month1.cust_id, month1.cust_name_last
FROM customer month1 INNER JOIN customer month2
ON month1.cust_id = month2.cust_id
AND YEAR(month2.order_date) = YEAR(month1.order_date)
AND MONTH(month2.order_date) - MONTH(month1.order_date) = 1;
If you want to find consecutive orders including another years (e.g 2013-12 => 2014-01), need to check overflows something like as follows
SELECT DISTINCT month1.cust_id, month1.cust_name_last
FROM customer month1 INNER JOIN customer month2
ON month1.cust_id = month2.cust_id
AND (YEAR(month2.order_date) - YEAR(month1.order_date)) * 12 + (MONTH(month2.order_date) - MONTH(month1.order_date)) = 1;
If preceding SQL does not work for you, We are highly appreciated when you post your schema and sample data on sqlFiddle http://www.sqlfiddle.com/.