Select results if the newest date is older than 30 days - mysql

I have a MySQL table with 2 fields: id_type and created_at
There are several rows with the same id_type and different timestamps. Eg:
3 - 2015-06-10 12:01:20
1 - 2015-03-21 04:14:10
1 - 2015-03-17 04:14:10
0 - 2015-05-06 21:43:00
3 - 2015-05-13 19:34:32
3 - 2015-07-18 03:47:55
I need to select id_type if the newest corresponding created_at is older than 30 days (Or in other words, any id_type that was last recorded more than 30 days ago)
Expected result:
1
0
I've tried:
SELECT id_type FROM table WHERE MAX(created_at) < DATE_SUB(NOW(), INTERVAL 30 day)
Which has given me the error:
invalid use of group function
How should I build it properly?

Try this,
SELECT id_type FROM table_b WHERE created_at IN (Select MAX(created_at) from table_b where created_at < DATE_SUB(NOW(), INTERVAL 30 day));

You can use this :
select id_type from `table` where `created_at` >= DATE_SUB(CURDATE(), INTERVAL 3 MONTH)

Related

How to retrieve data from previous 4 weeks (mySQL)

I am trying to write a query to get the last 4 weeks (Mon-Sun) of data. I want every week of data to be stored with an individual and shared table.
every week data store based on name if same name repeated on single week amt should sum and if multiple name it should be show data individual, To see an example of what I am looking for, I have included the desired input and output below.
this is my table
date
amt
name
2022-04-29
5
a
2022-04-28
10
b
2022-04-25
11
a
2022-04-23
15
b
2022-04-21
20
b
2022-04-16
20
a
2022-04-11
10
a
2022-04-10
5
b
2022-04-05
5
b
i want output like this
date
sum(amt)
name
2022-04-25 to 2020-04-29
16
a
2022-04-25 to 2020-04-29
10
b
2022-04-18 to 2022-04-24
35
b
2022-04-11 to 2022-04-17
30
a
2022-04-04 to 2022-04-10
10
b
I would appreciate any pointers or 'best-practises' which I should employ to achieve this task.
You can try to use DATE_ADD with WEEKDAY get week first day and end day.
SELECT
CASE WHEN
weekofyear(`date`) = weekofyear(NOW())
THEN 'current week'
ELSE
CONCAT(date_format(DATE_ADD(`date`, interval - WEEKDAY(`date`) day), '%Y-%m-%d'),' to ',date_format(DATE_ADD(DATE_ADD(`date`, interval -WEEKDAY(`date`) day), interval 6 day), '%Y-%m-%d'))
END 'date',
SUM(amt)
FROM T
GROUP BY
CASE WHEN
weekofyear(`date`) = weekofyear(NOW())
THEN 'current week'
ELSE
CONCAT(date_format(DATE_ADD(`date`, interval - WEEKDAY(`date`) day), '%Y-%m-%d'),' to ',date_format(DATE_ADD(DATE_ADD(`date`, interval -WEEKDAY(`date`) day), interval 6 day), '%Y-%m-%d'))
END
sqlfiddle
EDIT
I saw you edit your question, you can just add name in group by
SELECT
CONCAT(date_format(DATE_ADD(`date`, interval - WEEKDAY(`date`) day), '%Y-%m-%d'),' to ',date_format(DATE_ADD(DATE_ADD(`date`, interval -WEEKDAY(`date`) day), interval 6 day), '%Y-%m-%d')) 'date',
SUM(amt),
name
FROM T
GROUP BY
CONCAT(date_format(DATE_ADD(`date`, interval - WEEKDAY(`date`) day), '%Y-%m-%d'),' to ',date_format(DATE_ADD(DATE_ADD(`date`, interval -WEEKDAY(`date`) day), interval 6 day), '%Y-%m-%d')),
name
ORDER BY 1 desc
sqlfiddle
This is in SQL Server, and just a mess about. Hopefully it can be of some help.
with cteWeekStarts
as
(
select
n,dateadd(week,-n,DATEADD(week, DATEDIFF(week, -1, getdate()), -1)) as START_DATE
from
(values (1),(2),(3),(4)) as t(n)
), cteStartDatesAndEndDates
as
(
select *,dateadd(day,-1,lead(c.start_date) over (order by c.n desc)) as END_DATE
from cteWeekStarts as c
)
,cteSalesSumByDate
as
(
select s.SalesDate,sum(s.salesvalue) as sum_amt from
tblSales as s
group by s.SalesDate
)
select c3.n as WeekNum,c3.START_DATE,isnull(c3.END_DATE,
dateadd(day,6,c3.start_date)) as END_DATE,
(select sum(c2.sum_amt) from cteSalesSumByDate as c2 where c2.SalesDate
between c3.START_DATE and c3.END_DATE) as AMT
from cteStartDatesAndEndDates as c3
order by c3.n desc

Show number of lower and higher values in SQL

I have a certain problem while trying to make an SQL. I have a table with the following format and data.
id
value
date
12
3
2020-06-01
12
4
2020-06-09
12
1
2020-06-20
5
4
2020-06-11
5
5
2020-06-17
My goal is to make something like that:
id
lower
higher
12
1
1
5
0
1
This looks for the value of the oldest row IN specific interval (ex. 100 days)and it compares it with all dates after that if their values are higher and lower and return the count.
I do have something that works but it requires more queries:
One to group take all ids with dates in the interval of xx days
SELECT id FROM table
WHERE date >= CURDATE() - INTERVAL 30 DAY GROUP BY id
ORDER BY id ASC;
And then I loop through each row and get its lower and higher values.
SELECT
*
FROM
(
SELECT
COUNT(*) AS higher, id
FROM
`table`
WHERE
id = 12 AND date > CURDATE() - INTERVAL 30 DAY AND value > (
SELECT value FROM table
WHERE table.date >= CURDATE() - INTERVAL 30 DAY AND id = 12
ORDER BY `table`.`date` ASC LIMIT 1
)
) AS t1,(
SELECT
COUNT(*) AS deteriorated_placements
FROM
`table`
WHERE
id = 12 AND date > CURDATE() - INTERVAL 30 DAY AND value < (
SELECT value FROM table
WHERE table.date >= CURDATE() - INTERVAL 30 DAY AND id = 12
ORDER BY `table`.`date` ASC LIMIT 1
)
) AS t2;
The problem with that is that I do around 40 more queries. I know it maybe is not a big issue but
Is there a way to somehow combine those 2 queries?
Use first_value():
select id,
sum(value < value_1) as lower,
sum(value > value_1) as higher
from (select t.*,
first_value(value) over (partition by id order by date) as value_1
from t
) t
group by id;

Get user who has transaction in last 7 days, and only one transaction in 30 days

I have a table like below, today is 2021-05-25.
UserId
TransactionDate
1
2021-05-21
1
2021-05-12
4
2021-05-25
1
2021-04-03
3
2021-05-15
3
2021-04-02
4
2021-03-25
I want the output is 4.
Since 1 has transaction within 7 days, but 2 transactions within 30days.
3 don't have any transaction within 7 days.
Only 4 has transaction within 7 days, and that's the only transaction within 30 days.
I can only filtered by the first condition using
WHERE t.TransactionDate > to_date('2021-05-17')
GROUP BY 1
Can anyone help how to apply both condition?
You can use aggregation with having:
select userid
from t
where transactiondate >= curdate() - interval 30 day
group by userid
having count(*) = 1 and
max(transactiondate) >= curdate() - interval 7 day;
If you want the transaction detail, it is a little more complciated:
select t.*
from transactions t
where t.transactiondate >= curdate() - interval 7 day and
not exists (select 1
from transactions t2
where t2.userid = t.userid and
t2.transactiondate >= curdate() - interval 30 day and
t2.transactiondate <> t.transactiondate
);

Sql query not returning max value

I have written the following query to get the value with the max issue_id. But I get the issue_id 14 for book_id 2. What I want is to get issue_id 16 when book_id is 2. And issue_id 15 when book_id is 3 and so on.
SELECT issue.issue_id AS issue_id, issue.issue_date, issue.student_id, books.availability,
CASE WHEN NOW() > DATE_ADD(issue.issue_date, INTERVAL 20 DAY)
THEN 10*DATEDIFF(NOW(), DATE_ADD(issue.issue_date, INTERVAL 20 DAY))
ELSE 0 END AS fine_amount
FROM issue
INNER JOIN books
ON issue.book_id=books.book_id
WHERE books.book_id=2
HAVING MAX(issue.issue_id)
Use the ORDER BY .. LIMIT 1 to get the highest value
SELECT issue.issue_id AS issue_id, issue.issue_date, issue.student_id, books.availability,
CASE WHEN NOW() > DATE_ADD(issue.issue_date, INTERVAL 20 DAY)
THEN 10*DATEDIFF(NOW(), DATE_ADD(issue.issue_date, INTERVAL 20 DAY))
ELSE 0 END AS fine_amount
FROM issue
INNER JOIN books
ON issue.book_id=books.book_id
WHERE books.book_id=2
ORDER BY issue.issue_id DESC LIMIT 1

mysql query for grabbing multiple date ranges

I seem to be having a bit of trouble coming up a query to achieve what I want. I have a table like the following..
| Date(TIMESTAMP) | Count |
|---------------------|-------|
| 2016-02-01 01:00:00 | 52 |
| 2016-01-05 11:30:00 | 14 |
| 2016-02-01 04:20:00 | 36 |
| ... | ... |
The table has about 40,000 rows. What I would like to do is grab the totals for multiple date ranges so I end up with the following...
| Period | Total |
|------------|-------|
| All | 10245 |
| Past year | 1401 |
| Past month | 104 |
| Past week | 26 |
Currently I am running through a loop in my PHP script and doing an individual query for each date range I'm looking for. Actually there are about 10 queries I'm doing per loop to grab different stats but for the example I'm simplifying it. This takes forever and I am hoping there is a more elegant way to do this, however I've spent quite a bit of time now trying different things and researching and have gotten nowhere. I understand how to use CASE to group but not when a record may need to be in multiple bins. Any help?
Try this UNION query:
SELECT 'All', COUNT(*) AS Total FROM yourTable
UNION
SELECT 'Past year', COUNT(*) AS Total
FROM yourTable
WHERE DATE(TIMESTAMP) > DATE_ADD(NOW(), INTERVAL -1 YEAR)
UNION
SELECT 'Past month', COUNT(*) AS Total
FROM yourTable
WHERE DATE(TIMESTAMP) > DATE_ADD(NOW(), INTERVAL -1 MONTH)
UNION
SELECT 'Past week', COUNT(*) AS Total
FROM yourTable
WHERE DATE(TIMESTAMP) > DATE_ADD(NOW(), INTERVAL -1 WEEK)
1st. get known to function getting first date of year, first date of month and first date of week.
Then compose your sql using count and filter with first and last date of different period.
ref:
MySQL Select First Day of Year and Month
month
https://stackoverflow.com/a/19259159/1258492
week https://stackoverflow.com/a/11831133/1258492
select 'All' as period, count(1) from
tbl
union
select 'Past Year' as period, count(1) from
tbl
where timestamp between
MAKEDATE(year(now())-1,1) and
last_day(MAKEDATE(year(now())-1,1) + interval 11 month)
union
select 'Past Month' as period, count(1) from
tbl
where timestamp between
LAST_DAY(NOW() - INTERVAL 2 MONTH) + INTERVAL 1 DAY and
LAST_DAY(NOW() - INTERVAL 1 MONTH)
union
select 'Past Week' as period, count(1) from
tbl
where timestamp between
adddate(curdate(), INTERVAL 1-DAYOFWEEK(curdate())-7 DAY) and
adddate(curdate(), INTERVAL 7-DAYOFWEEK(curdate())-7 DAY) ;
You may use subqueries. Use one subquery per time breakdown like so:
SELECT everything, 'past year'
FROM
(
SELECT sum(c) AS 'everything'
FROM reports
) t1,
(
SELECT sum(c) AS 'past year'
FROM reports
WHERE d >= DATE_ADD(CURDATE(), INTERVAL -1 YEAR)
) t2