Get nearest continuous date period MySQL - php

I have this MySQL table:
| Date | Room | State |
|2015-06-15 | 26 | 1 |
|2015-06-16 | 26 | 1 |
|2015-06-17 | 26 | 1 |
|2015-06-18 | 26 | 1 |
|2015-06-20 | 26 | 1 |
|2015-06-21 | 26 | 0 |
|2015-06-22 | 26 | 0 |
|2015-06-23 | 26 | 1 |
|2015-06-24 | 26 | 0 |
|2015-06-30 | 26 | 1 |
|2015-07-01 | 26 | 1 |
I want to get the first date of the beginning of useful nearest (it means continuous day, State = 1) booking period (for example, 2 days).
How can I do it?

SELECT d.*
FROM dates d
WHERE EXISTS(SELECT `Date`
FROM dates
WHERE `Room` = d.`Room`
AND `Date` = Date_add(d.`Date`, INTERVAL 1 DAY)
AND `State` = 1)
AND d.`State` = 1;
for 2 Days.
SET #days=3;
SELECT d.*
FROM dates d
WHERE (SELECT Count(`date`)
FROM dates
WHERE `Room` = d.`Room`
AND `Date` <= Date_add(d.`Date`, INTERVAL #days - 1 DAY)
AND `Date` >= d.`Date`
AND `State` = 1) >= #days
AND d.`State` = 1;
for dynamic days value.
And the testdata I used:
create table Dates(
`Date` DATE,
`Room` INT DEFAULT 26,
`State` BOOL DEFAULT 0);
INSERT INTO Dates (`Date`,`State`) VALUES
('2015-01-01',1),
('2015-01-02',0),
('2015-01-03',1),
('2015-01-04',1),
('2015-01-05',0),
('2015-01-06',1),
('2015-01-07',1),
('2015-01-08',1),
('2015-01-09',0),
('2015-01-10',1),
('2015-01-11',1),
('2015-01-12',1),
('2015-01-13',1);
The query returns actually all posible dates. To get only one date add a LIMIT 1 at the end of the statement. But maybe it can be help full to get later Startdays that are Possible.
The second query returns with the testdata the following Dates:
2015-01-06 26 1
2015-01-10 26 1
2015-01-11 26 1

Related

php mysql select by month between records

I've this MySQL table my_table:
+-------+------------+-----------+
|Student| Date | Classroom |
+-------+------------+-----------+
| 1 | 2018-01-01 | 101 |
| 2 | 2018-01-01 | 102 |
| 3 | 2018-01-01 | 103 |
| 1 | 2018-03-01 | 104 |
| 2 | 2018-06-01 | 103 |
| 3 | 2018-09-01 | 104 |
| 1 | 2018-11-01 | 106 |
| 2 | 2018-12-01 | 101 |
+-------+------------+-----------+
The students stay in the assigned classroom till changed.
I'm trying to get which classroom they were in for a certain month.
For example in October(10), student 1 was in 104, 2 was in 103, and 3 was in 104.
I'm really unsure on how to proceed with this one so any help is appreciated.
Currently using this query based on Strawberry answer
SELECT x.*
FROM my_table x
LEFT OUTER JOIN my_table y
ON y.student = x.student
AND y.date < x.date
WHERE x.date <= LAST_DAY('2018-10-01')
GROUP BY student
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(Student INT NOT NULL, Date DATE NOT NULL, Classroom INT NOT NULL,PRIMARY KEY(student,classroom));
INSERT INTO my_table VALUES
(1,'2018-01-01',101),
(2,'2018-01-01',102),
(3,'2018-01-01',103),
(1,'2018-03-01',104),
(2,'2018-06-01',103),
(3,'2018-09-01',104),
(1,'2018-11-01',106),
(2,'2018-12-01',101);
SELECT x.*
FROM my_table x
JOIN
( SELECT student
, MAX(date) date
FROM my_table
WHERE date <= LAST_DAY('2018-10-01')
GROUP
BY student
) y
ON y.student = x.student
AND y.date = x.date;
+---------+------------+-----------+
| Student | Date | Classroom |
+---------+------------+-----------+
| 1 | 2018-03-01 | 104 |
| 2 | 2018-06-01 | 103 |
| 3 | 2018-09-01 | 104 |
+---------+------------+-----------+
Here's a go at it (snippet to go in a stored procedure; assumes table called example & output to table months). It produces a row per student for each month of the range.
drop table months;
create table months (month date, student integer, classroom integer);
set #month = (select min(date) from example);
start_loop: LOOP
insert into months select #month, s1.student, classroom from
(select student, max(date) as maxdate from example where date <= #month group by student) s1
join example s2 on s1.student = s2.student and maxdate = date;
if #month = (select max(date) from example) then
leave start_loop;
end if;
set #month = #month + interval 1 month;
END LOOP start_loop;
Let's break the problem into two parts. Firstly, find all the rooms which have been allocated to student A so far and sort them using the date. Next, find the record which is just before or equal to the required month.
For example:
Consider student 1. We get
+-------+------------+-----------+
|Student| Date | Classroom |
+-------+------------+-----------+
| 1 | 2018-01-01 | 101 |
| 1 | 2018-03-01 | 104 |
| 1 | 2018-11-01 | 106 |
+-------+------------+-----------+
Now, let's say for month June we try to find month just less than or equal to 2018-06-01 to get the required room number. I hope this will help.

Find Upcoming birthdays with Mysql

I want to select the next upcoming birthdays in MYSQL.
My date is stored as: 02/19/1981 and not in a date field. I think it has to sort by day and month and not year but i can not find out how.
How can i do this? This is the query till now:
$sql = "SELECT * FROM wp_postmeta WHERE meta_key='_web_date' ORDER BY ....";
If it's possible for you change the date column to type date.
Otherwise try this:
SELECT month(str_to_date(birthdayColumn, "%m/%d/%Y")) as month, day(str_to_date(birthdayColumn, "%m/%d/%Y")) as day FROM yourTable order by month, day;
Result:
+-------+------+
| month | day |
+-------+------+
| 1 | 12 |
| 2 | 19 |
| 9 | 10 |
| 12 | 15 |
+-------+------+
You can use the php date() function. For example ate('Y-m-d',strtotime("+7 day")); then create a sql query which selects dates which are in the upcoming 7 days
This is a test environment.
CREATE TEMPORARY TABLE `birthdays` (
`id` int(4),
`name` VARCHAR(50),
`dob` CHAR(10)
) ENGINE=MEMORY;
INSERT INTO birthdays VALUES (1,'Alice', '02/19/1951'), (2,'Bob', '09/10/2015'), (3,'Carol', '12/15/2000'), (4,'Doug', '01/12/2011');
I created this function to get the next birthday. The logic may throw some interesting results over 29th Feb / 1st March.
DELIMITER $$
CREATE FUNCTION `next_birth_day`(d_dob DATE) RETURNS DATE
DETERMINISTIC
BEGIN
/* NOTE: this logic ignores the handling of leap years */
/* MySQL will happily construct invalid leap years and they are ordered
between 29/2 & 1/3 in this code. */
DECLARE d_today DATE;
DECLARE d_this_year_bday DATE;
DECLARE d_next_year_bday DATE;
SET d_today = DATE(NOW());
SET d_this_year_bday = CONCAT(YEAR(d_today), '-', MONTH(d_dob), '-', DAY(d_dob));
SET d_next_year_bday = CONCAT(YEAR(d_today)+1, '-', MONTH(d_dob), '-', DAY(d_dob));
RETURN IF( d_this_year_bday < d_today, d_next_year_bday, d_this_year_bday);
END
$$
DELIMITER ;
Then you can do a query and order by next_birth_day:
SELECT *, str_to_date(dob, "%m/%d/%Y") AS dob_dt,
next_birth_day(str_to_date(dob, "%m/%d/%Y")) AS next_bday
FROM birthdays
ORDER BY next_birth_day(str_to_date(dob, "%m/%d/%Y")) ASC
giving results like this:
+------+-------+------------+------------+------------+
| id | name | dob | dob_dt | next_bday |
+------+-------+------------+------------+------------+
| 3 | Carol | 12/15/2000 | 2000-12-15 | 2015-12-15 |
| 4 | Doug | 01/12/2011 | 2011-01-12 | 2016-01-12 |
| 1 | Alice | 02/19/1951 | 1951-02-19 | 2016-02-19 |
| 2 | Bob | 09/10/2015 | 2015-09-10 | 2016-09-10 |
+------+-------+------------+------------+------------+

How to select data from multiple tables based on different time ranges?

I have two tables in MySQL:
visits
points
visits table looks like the following:
+-------+-------------------+-----------+
| id | date | user_id |
+-------+-------------------+-----------+
| 1 |2014-08-01 05:23:00| 43 |
| 2 |2014-08-01 14:41:00| 21 |
| 3 |2014-08-02 23:54:00| 43 |
| 4 |2014-08-03 03:21:00| 43 |
| 5 |2014-08-03 04:19:00| 34 |
| 6 |2014-08-03 11:33:00| 43 |
| 7 |2014-08-04 12:21:00| 43 |
| 8 |2014-08-05 01:55:00| 43 |
| 9 |2014-08-06 06:13:00| 43 |
| 10 |2014-08-07 19:47:00| 43 |
+-------+-------------------+-----------+
points table looks like the following:
+-------+-------------------+-----------+-------+----------+
| id | date | user_id | points| status |
+-------+-------------------+-----------+-------+----------+
| 1 |2014-08-01 04:33:00| 43 | 10 | 0 |
| 2 |2014-08-02 05:21:00| 21 | 23 | 0 |
| 3 |2014-08-02 09:01:00| 43 | 32 | 1 |
| 4 |2014-08-02 01:21:00| 43 | 21 | 0 |
| 5 |2014-08-03 23:23:00| 34 | 54 | 0 |
| 6 |2014-08-04 20:34:00| 43 | 11 | 0 |
| 7 |2014-08-04 17:54:00| 43 | 9 | 0 |
| 8 |2014-08-04 03:45:00| 43 | 34 | 0 |
| 9 |2014-08-06 08:23:00| 43 | 76 | 0 |
| 10 |2014-08-07 11:43:00| 43 | 52 | 0 |
+-------+-------------------+-----------+-------+----------+
I want execute only 1 query and achieve the following.
I'd like to count the rows in the visits table where the user_id = 43 and the date is between 2014-08-01 and 2014-08-03.
I also want to count the rows, sum the points in the points table where user_id = 43 and the date is between 2014-08-01 and 2014-08-03 and the status is 0.
After that, in the same query, I'd like to select the same as above, but in a different timeframe, like: 2014-08-04 and 2014-08-07.
Is there any query out there which can solve this problem for me?
(I'm actually doing this because I'd like to get data for one of my jQuery chart which is called: Morris.js. I'd like to get 12 datasets if the visitor selects a time range and divide it based on the days, the visitor selected. For example: if he selects: 2014-08-01 till 2014-08-01, I want to display him 12 datasets of that day. But if he selects for example: 2014-08-01 till 2014-08-06, then I'd want to display him the data for the 6 day divided by 12.)
If you don't understand something here, just let me know and I'll explain it better. The point is that I'd like to collet the datasets and draw the chart based on the time range to the visitor. Is that above MySQL logic a good solution for my issue?
EDIT:
As per request I'm showing the desired result in here:
+---------------------+-----------+-------+-------+-------------+
| date | user_id | points| visits| points_count|
+---------------------+-----------+-------+-------+-------------+
|2014-08-01-2014-08-03| 43 | 31 | 4 | 2 |
|2014-08-04-2014-08-07| 43 | 182 | 4 | 5 |
+---------------------+-----------+-------+-------+-------------+
I hope I've calculated everything correctly.
ok so this took a little work because you have to join the two tables independantly of eachother.. the reason being is because one can't have the status of 1 and the other can.. so with that in mind this query will return exactly what you want.
QUERY:
SELECT
t.join_date as 'Time Frame',
t1.user_id,
t.num_visits,
t1.num_points,
t1.total_points
FROM
( SELECT
CASE
WHEN DATE(date) >= '2014-06-01' AND DATE(date) <= '2014-07-10' THEN 1
WHEN DATE(date) >= '2014-08-05' AND DATE(date) <= '2014-08-07' THEN 2
ELSE 3
END AS grouping_col,
CONCAT(MIN(DATE(date)), ' - ', MAX(DATE(date))) as join_date,
COUNT(id) as num_visits
FROM visits
WHERE user_id = 43
GROUP BY grouping_col
)t
LEFT JOIN
( SELECT
CASE
WHEN DATE(date) >= '2014-06-01' AND DATE(date) <= '2014-07-10' THEN 1
WHEN DATE(date) >= '2014-08-05' AND DATE(date) <= '2014-08-07' THEN 2
ELSE 3
END AS grouping_col,
CONCAT(MIN(DATE(date)), ' - ', MAX(DATE(date))) as join_date,
user_id,
COUNT(id) as num_points,
SUM(points) as total_points
FROM points
WHERE user_id = 43
AND status = 0
GROUP BY grouping_col
)t1 ON t1.grouping_col = t.grouping_col
WHERE t.grouping_col IN(1, 2) OR t1.grouping_col IN(1, 2)
NOTE:
you can add as many timeframes to this by just adding more rows to the CASE statement...
SEE DEMO:
FIDDLE
A better option may be to actually use a stored procedure and set a beginning date param and an end date param so you can pick any dates you want
The only approach which comes to mind is to do two distinct query and use UNION ALL
SELECT *
FROM
(SELECT
count(v.id) AS visit_count,
count(p.id) AS point_count,
sum(p.points) AS points
FROM visits v1
JOIN points p1
ON v1.user_id = p1.user_id
WHERE v1.user_id = 43
AND DATE(v1.date) BETWEEN '2014-08-01' AND '2014-08-03'
AND p1.status = 0
UNION ALL
SELECT
count(v.id) AS visit_count,
count(p.id) AS point_count,
sum(p.points) AS points
FROM visits v2
JOIN points p2
ON v2.user_id = p2.user_id
WHERE v2.user_id = 43
AND DATE(v2.date) BETWEEN '2014-08-04' AND '2014-08-07'
AND p2.status = 0
) temp
You could try:
select count(id)
from visits
join points on points.user_id = visits.user_id
where date between 2014-08-04 00:00:00 and 2014-08-07 00:00:00
and visits.user_id = 43

Fetching last 30 days data from mysql table and grouping them by date

Here is how my table looks like
| total_hit |success_hit | date_time |
| 12 | 12 | 01-11-2009 07:32:44 |
| 12 | 11 | 01-11-2009 08:33:49 |
| 12 | 10 | 01-11-2009 09:08:24 |
| 12 | 11 | 01-12-2009 10:33:57 |
| 12 | 12 | 01-12-2009 11:37:34 |
| 12 | 11 | 01-12-2009 12:23:49 |
I am fetching the data from the table for the past 30 days using the following query:
SELECT *
FROM my_table
WHERE DATE(date_time) >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
what I want to do is group the returned data in terms of date and calculate the percentage success (success_hit/total_hit)*100
Something like
Date: 01-11-2009 Percentage: x
Date: 01-12-2009 Percentage: y
any ideas?
select (success/total)*100 as perc_success, Date(date_time) from
(select sum(success_hit) as success, sum(total_hit) as total,
date_time from my_table
where DATE(date_time) >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
group by Date(date_time) )
tbl
This should work!!!
Try this
SELECT (sum(success_hit)/sum(total_hit)*100) AS `Percentage`,
DATE(date_time) AS `Date`
FROM my_table
WHERE DATE(date_time) >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
GROUP BY DATE(date_time);

sum hits for every week in mysql

I have a table with number of page views per day. Something like this:
+------+------------+------+----------+
| id | date | hits | mangaID |
+------+------------+------+----------+
| 4876 | 1331843400 | 132 | 13 |
+------+------------+------+----------+
| 4876 | 1331929800 | 24 | 236 |
+------+------------+------+----------+
| 7653 | 1331929800 | 324 | 13 |
+------+------------+------+----------+
I'm trying to get sum hits from last week with the below code:
SELECT sum(hits) as hits FROM om_manga_views WHERE DATE_SUB(CURDATE(),INTERVAL 1 week) <= date and mangaID = '13'
My problem is that I'm storing date as time using strtotime in date's field as int type.
So how can i get what i want!?
Try this:
select sum(hits) hitCount from t
where from_unixtime(date) >= current_date() - interval 1 week and mangaId = 11
Here is the fiddle to play with.
I slightly changed your data because the records you provided are older than 7 days, so the sum would return 0.

Categories