First 5 entries for a single user - mysql

I am using PostgreSQL. I need to get the dates for the first 5 transactions of every user on my DB.
Transaction - trans.id, trans.date, trans.cust_id, trans.value
Customer - cust.id, cust.created_at
I need to get the date of the first 5 transactions for all the customers.

Try this query:
SELECT cust_id, date
FROM (
SELECT cust_id,
date,
row_number() OVER (partition by cust_id
ORDER BY date, id ) rn
FROM Transaction
) as alias
WHERE rn <= 5
ORDER BY 1,2
demo: http://sqlfiddle.com/#!15/cfd2e/4

Related

SQL Moving window over two level of groupby

I have the following table of orders for users like the following:
CREATE TABLE orders (
order_id UUID,
user_id UUID,
date date,
order_type integer
);
I want to write SQL to do the following:
For every order want to compute the number of orders the user has within a previous week (7 days).
Write the following, but it counts the number of orders for each user but not for two levels of groupby.
SELECT order_id, user_id,
COUNT(order_id) OVER(PARTITION BY user_id ORDER BY date ROWS BETWEEN 7 PRECEDING AND CURRENT ROW) as num_orders_7days
FROM orders
You should use RANGE clause instead of ROWS with the proper date intervals:
SELECT order_id, user_id, date,
COUNT(order_id) OVER (
PARTITION BY user_id
ORDER BY date
RANGE BETWEEN INTERVAL 7 day PRECEDING AND INTERVAL 1 day PRECEDING
) as num_orders_7days
FROM orders;
See the demo.

MySQL - SQL query to get the customer ids and date of 20th transaction

I am having trouble coming up with a query to get a list of customer ids and the date of their 20th purchase.
I am given a table called transactions with the column name customer_id and purchase_date. Each row in the table is equal to one transaction.
customer_id
purchase_date
1
2020-11-19
2
2022-01-01
3
2021-12-05
3
2021-12-09
3
2021-12-16
I tried to do it like this and assumed I would have to count the number of times the customer_id has been mentioned and return the id number if the count equals 20.
SELECT customer_id, MAX(purchase_date)
FROM transactions
(
SELECT customer_id,
FROM transactions
GROUP BY customer_id
HAVING COUNT (customer_id) =20
)
How can I get this to return the list of customer_id and only the date of the 20th transaction?
You need to select the rows of transactions belonging to the customer_id and filter the result by the 20th row
SELECT * FROM (
SELECT customer_id, purchase_date, ROW_NUMBER() OVER(
PARTITION BY customer_id
ORDER BY purchase_date DESC
) AS nth
FROM transactions
) as t WHERE nth = 20
My solution:
select *
from transactions t
inner join (
select
customer_id,
purchase_date,
row_number() over (partition by customer_id order by purchase_date) R
from transactions) x on x.purchase_date=t.purchase_date
and x.customer_id=t.customer_id
where x.R=20;
see: DBFIDDLE
For MySQL5.7, see: DBFIDDLE
set #r:=1;
select *
from transactions t
inner join (
select
customer_id,
purchase_date,
#r:=#r+1 R
from transactions) x on x.purchase_date=t.purchase_date
and x.customer_id=t.customer_id
where x.R=20;
Use row_number = 20
SELECT
customer_id,
purchase_date as date_t_20
FROM
(
SELECT
customer_id,
purchase_date,
Row_number() OVER (
PARTITION BY customer_id
ORDER BY purchase_date) AS rn
FROM transactions
) T
WHERE rn = 20;

A mySQL query for returning customers that make multiple purchases and the specific time of the 5th purchase

"loyal" customers are considered loyal if they have purchased at least 5 times.
I am trying to build an SQL query which returns only "loyal" customers along with the day on
which they become "loyal" customers (the day of their 5th transaction).
user_id
purchase_ts
f594fsae
2021-07-21
........
............
Ideally the desired output would be as follows
loyal_user_id
Loyal_Moment
f594fsae
2021-07-29
..............
............
I tried creating a new table as follows:
SELECT user_id, purchase_ts
FROM Customers
WHERE user_id IN (
SELECT user_id
FROM Customers
GROUP BY user_id
HAVING COUNT (user_id) >=5
)
But I am having trouble, any suggestions?
On MySQL 8 you could use:
with cte as
( select *,
row_number() over (partition by user_id order by purchase_ts asc) row_num
from accounts
)
select user_id,purchase_ts
from cte
where row_num >=5;
Result:
user_id purchase_ts
f594fsae 2021-07-25
f632fsae 2021-07-25
Demo
Since MySQL introduced the support of subquery a long time ago, we have been using its techniques in some MySQL-version-nonspecific scenarios. In this case, we can use a correlated subquery to get exactly the fifth purchase_ts by using the LIMIT [OFFSET] clause. The WHERE clause is used to exclude those purchase_id which doesn't have a fifth purchase_ts.
select distinct user_Id,
(select purchase_ts from purchase where user_id=p.user_id order by purchase_ts limit 4,1) as loyal_time
from purchase p
where (select purchase_ts from purchase where user_id=p.user_id order by purchase_ts limit 4,1) is not null;

Selecting the latest row for each customer that matches these params

I have an SQL table that stores reports. Each row has a customer_id and a building_id and when I have the customer_id, I need to select the latest row (most recent create_date) for each building with that customer_id.
report_id customer_id building_id create_date
1 1 4 1553561789
2 2 5 1553561958
3 1 4 1553561999
4 2 5 1553562108
5 3 7 1553562755
6 3 8 1553570000
I would expect to get report id's 3, 4, 5 and 6 back.
How do I query this? I have tried a few sub-selects and group by and not gotten it to work.
If you are using MySQL 8+, then ROW_NUMBER is a good approach here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY customer_id, building_id
ORDER BY create_date DESC) rn
FROM yourTable
)
SELECT
report_id,
customer_id,
building_id,
create_date
FROM cte
WHERE rn = 1;
If there could be more than one customer/building pair tied for the latest creation date, and you want to capture all ties, then replace ROW_NUMBER with RANK, and use the same query.
Another variation:
SELECT a.*
FROM myTable a
WHERE a.create_date = (SELECT MAX(create_date)
FROM myTable b
WHERE b.customer_id = a.customer_id
AND b.building_id = a.building_id)
Can try doing a search for "effective dated records" to see various approaches.

MYSQL query to get records with value that increased most between two dates

I have a MySQL table ScoreArchive with following fields:
ID (int), primary key
Date (date)
Score (int)
I record in the table the Score of each ID every day.
Now I wish to find the IDs that have the top score increase between, for example, 2011-04-22 and 2011-05-31.
How can I find these using a MySQL query?
Try something like:
select id, max(score) - min(score) as diff ... group by id order by diff desc
Edit (following up on the comment):
Or something like:
select id, final_scores.score - start_scores.score as diff
from (
select id, min(date) as min_date, max(date) as max_date
from scores
where date between ...
group by id
) as ranges
join scores as final_scores
on final_scores.date = ranges.min_date
join scores as start_scores
on start_scores.date = ranges.max_date
where ...
order by diff desc
SELECT score FROM ScoreArchive WHERE date BETWEEN 2011-04-22 AND 2011-05-31 ORDER BY score DESC;
That's how i would do it in pgsql i am guessing that mysql is the same