Show number of lower and higher values in SQL - mysql

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;

Related

How to populate number for missing dates?

I have a table that look like this
date counts
Sep-01 1
Sep-05 5
Sep-10 30
As you can see the dates are jumping across and is not continuous. I want the final results to be populated for all calendar dates, and the value for the missing dates should be equal to the previous date. I played around with several SQL analytics functions but it doesn't seem to solve the problem. Any tips?
date counts
Sep-01 1
Sep-02 1
Sep-03 1
Sep-04 1
Sep-05 5
Sep-06 5
Sep-07 5
Sep-08 5
Sep-09 5
Sep-10 30
Sep-11 30
...
Here is solution:
CREATE TABLE datadate(startdate DATETIME, cnt INT);
INSERT INTO datadate VALUES('2020-05-25',1);
INSERT INTO datadate VALUES('2020-05-27',2);
INSERT INTO datadate VALUES('2020-05-30',5);
SELECT * FROM datadate;
WITH RECURSIVE cte_name (cnt,ddate) AS (
SELECT cnt,MIN(startdate) AS ddate FROM datadate
UNION ALL
SELECT
CASE
WHEN (SELECT cnt FROM datadate WHERE startdate=DATE_ADD(ddate, INTERVAL 1 DAY)) IS NULL THEN cnt
ELSE (SELECT cnt FROM datadate WHERE startdate=DATE_ADD(ddate, INTERVAL 1 DAY))
END AS cnt,
DATE_ADD(ddate, INTERVAL 1 DAY)
FROM cte_name
WHERE ddate < (SELECT MAX(startdate) FROM datadate)
)
SELECT * FROM cte_name;
Input:
Output:

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

How to get the COUNT of this mySQL query?

How can I just get the number of rows on the below query?
select
hash,page,timestamp, count(*) as total
from behaviour
group by hash,page
having total > 2 AND timestamp >= Now() - interval 5 minute
Solution by just querying:
SELECT COUNT(*)
FROM (
select
hash,page,timestamp, count(*) as total
from behaviour
group by hash,page
having total > 2 AND timestamp >= Now() - interval 5 minute) AS t1

Change MySql value based on time that has past

I have the following table:
user_id post_streak streak_date streak first_name club_id
-------- ----------- ------------ --------- ----------- --------
18941684 1 2015-05-05 15:36:18 3 user 1000
I want to change streak to 0 if it has been longer then 12 days.
current query:
select
first_name, streak, user_id from myTable
where
club_id = 1000
and
post_streak = 1
and
streak_date between date_sub(now(),INTERVAL 12 DAY) and now()
order by streak desc;
Which doesn't show results older then 12 days. I want to show all results but change "streak" to 0 if it has been longer the 12 days.
What is the best way to go about this?
UPDATE table
SET (streak)
VALUES (0)
WHERE streak_date < DATEADD(DAY, -12, NOW() );
SELECT first_name, streak, user_id from myTable
WHERE
club_id = 1000
AND
post_streak = 1
ORDER BY streak DESC;
First query will set all streak values to 0 for records that have streak_date of more than 12 days ago
Second query will get a list of all your records that have a club_id of 1000 and a post_streak of 1
Put the condition in the select, rather than the where:
select first_name,
(case when streak_date between date_sub(now(), INTERVAL 12 DAY) and now()
then streak
else 0
end) as streak,
user_id from myTable
where club_id = 1000
order by streak desc;
I'm not sure if the post_streak condition is needed in the where clause.
http://sqlfiddle.com/#!9/d8bbd/6
select
user_id,
first_name,
streak_date,
IF(streak_date between date_sub(now(),INTERVAL 12 DAY) and now(),streak,0)
from myTable
where
club_id = 1000
and
post_streak = 1
order by streak desc;

fetch next last n element from table using my sql

I have a table like this to track visits of my site hourly:
id | year | month | day | hour | date | visit
1 1391 12 1 10 2012-11-10 15
... ... ... ... ... ... ...
I use this query to fetch last 7 days visitors amount.
SELECT Sum(visit), `day`, `month`, `year`, WEEKDAY(date) as wd
FROM tablename GROUP BY date ORDER BY date DESC LIMIT 7;
Now my question is this: how can i fetch 7 days before this 7 days?
(the year,day,month is my local date format and i want to change it one time on registering)
Use offset:
SELECT Sum(visit), `day`, `month`, `year`, WEEKDAY(date) as wd
FROM tablename
GROUP BY date
ORDER BY date DESC
LIMIT 7 OFFSET 7;
I don't like the idea of using LIMIT here to get the last 7 days, I much prefer a WHERE clause.
I would change your query above to:
SELECT SUM(visit), `day`, `month`, `year`, WEEKDAY(date) as wd
FROM tablename
WHERE date >= CURDATE() - INTERVAL 7 DAYS
GROUP BY date
ORDER BY date DESC;
Then to get the previous 7 days:
SELECT SUM(visit), `day`, `month`, `year`, WEEKDAY(date) as wd
FROM tablename
WHERE date BETWEEN CURDATE() - INTERVAL 14 DAYS AND CURDATE() - INTERVAL 8 DAYS
GROUP BY date
ORDER BY date DESC;
I also don't like the idea of storing your local date format in the table.. you are duplicating data and it should be easy enough to convert the date when querying.