I have a table that stores opening dates in 2 columns with the type Date. I need to select the entries which are open during a date range, but without taking the year in regard.
To prevent confusion I'll write all dates in the format YYYY-MM-DD or MM-DD.
Here's a simple example for the table.
| ID | Start | End |
| 1 | 2014-12-01 | 2014-12-31 |
| 2 | 2015-11-18 | 2016-01-20 |
| 3 | 2015-01-01 | 2016-01-18 |
| 4 | 2015-12-10 | 2015-12-20 |
Based on this post I'm able to look for entries that are in the same year. This query for example would give me the rows 1 and 4 if I'm looking for anything open between 12-13 and 12-15.
SELECT *
FROM Dates
WHERE
DATE_FORMAT(Start, "%m%d") <= DATE_FORMAT("2015-12-13", "%m%d") AND
DATE_FORMAT(End, "%m%d") >= DATE_FORMAT("2016-12-15", "%m%d")
Looking for entries between 12-01 and 01-13 won't work with this though.
Does anybody have an idea how I'd be able to do this?
Edit
Just so everybody interested has the testing table.
CREATE TABLE `Dates` (
`idDates` int(11) NOT NULL AUTO_INCREMENT,
`Start` date DEFAULT NULL,
`End` date DEFAULT NULL,
PRIMARY KEY (`idDates`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `Dates`
(`idDates`,
`Start`,
`End`)
VALUES
('1', '2014-12-01', '2014-12-31'),
('2', '2015-11-18', '2016-01-20'),
('3', '2015-01-01', '2016-01-18'),
('4', '2015-12-10', '2015-12-20');
Let me assume that you have two variables: #StartDate and #EndDate. Then you can write the logic as:
SELECT *
FROM Dates
WHERE (DATE_FORMAT(#StartDate, '%m%d') <= DATE_FORMAT(#EndDate, '%m%d') AND
DATE_FORMAT(Start, '%m%d') <= DATE_FORMAT(#StartDate, '%m%d') AND
DATE_FORMAT(End, '%m%d') >= DATE_FORMAT(#EndDate, '%m%d')
) OR
(DATE_FORMAT(#StartDate, '%m%d') > DATE_FORMAT(#EndDate, '%m%d') AND
DATE_FORMAT(Start, '%m%d') > DATE_FORMAT(#StartDate, '%m%d') AND
DATE_FORMAT(End, '%m%d') < DATE_FORMAT(#EndDate, '%m%d')
);
Related
I am implementing the cashback functionality with expiry feature. I am trying to redeem the partial amount based on early expiry date. I've already ordered the rows based on expiry date with the following mysql command.
SELECT * FROM `cashback` WHERE `user_id` = 1 and `used`= 'NO' AND IF(CONCAT(`point_expiry`) !='0000-00-00 00:00:00', `point_expiry` >= NOW(), NOW()) ORDER BY (case when CONCAT(`point_expiry`) = '0000-00-00 00:00:00' then 9999
else 1
end) ASC, `point_expiry` ASC
And the output for the following will be
id
amount
point_expiry
used
user_id
3
30
2023-02-24 00:00:00
NO
1
1
20
2023-02-25 00:00:00
NO
1
2
50
0000-00-00 00:00:00
NO
1
Now i want to redeem the value based on the above query result
Let say i want to redeem 35$ for the above result and the expected result will be
id
amount
point_expiry
used
used_amount
3
30
2023-02-24 00:00:00
NO
30
1
20
2023-02-25 00:00:00
NO
5
Here used_amount column represent the specific redeem value($35) redeemed based on amount column
Much appreciate your help!
This uses SUM(amount) OVER(ORDER BY ...) to calculate a running total and compares it to the balance -
SELECT *
FROM (
SELECT
`id`,
`amount`,
`point_expiry`,
`used`,
`amount` - GREATEST(SUM(`amount`) OVER (ORDER BY IF(`point_expiry` = '0000-00-00 00:00:00', 1, 0) ASC, `point_expiry` ASC, id ASC) - /* Here is your amount --> */ 35, 0) AS `used_amount`
FROM `cashback`
WHERE (`point_expiry` >= NOW() OR `point_expiry` = '0000-00-00 00:00:00')
AND `used` = 'NO'
AND `user_id` = 1
) t
WHERE `used_amount` > 0;
I have a from_time an to_time in my table.
one of the record is from_time: 19:00:00 and to_time: 01:30:00
if user select 12:30 AM or 11:00 PM.
how do i correctly find that it is between from_time and to_time.
Mysql query i tried:
SELECT * FROM `table` WHERE '19:00:00' >= from_time and '19:00:00' <= to_time
is not working.
You used value instead of column name
You can use as below query. You can change value as per your need.
Change Time value as per your need first.
First Option with Where
SELECT * FROM `table` WHERE from_time >= '00:00:00' and to_time <= '23:59:59'
Second option is between
SELECT * FROM `table` WHERE from_time between '00:00:00' and '23:59:59'
Your question does not show where the selected time is coming from. Is it in a column, is it something that the user sets in the SQL or is it sent through code?
If the time is set in the SQL then the way to do this is as follows:
SET #mytime := '19:00:00';
SELECT * FROM `table` WHERE CAST(#mytime AS TIME) BETWEEN from_time AND to_time;
where #mytime is the user set variable and assuming that from_time and to_time are time format.
My test table for the above was as follows:
CREATE TABLE `timetest` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`from_time` time DEFAULT NULL,
`to_time` time DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
with test data as:
INSERT INTO `timetest` (`id`, `from_time`, `to_time`) VALUES
(1, '09:00:00', '11:00:00'),
(2, '06:30:00', '14:00:00'),
(3, '14:29:10', '16:12:18'),
(4, '09:11:17', '23:00:01'),
(5, '18:00:00', '23:59:59'),
(6, '01:12:00', '11:59:44');
For to_times which go over midnight you could add 24hours and then test. For example
drop table if exists t;
create table t(from_time time, to_time time);
insert into t values
('18:00:00','20:00:00'),
('18:00:00','01:00:00'),
('16:00:00','18:00:00');
select from_time,to_time,
case when '19:00:00' between
from_time and
if(to_time < from_time,
addtime(to_time,'24:00:00'),
to_time)
then 'true'
else 'false'
end as truefalse
from t;
+-----------+----------+-----------+
| from_time | to_time | truefalse |
+-----------+----------+-----------+
| 18:00:00 | 20:00:00 | true |
| 18:00:00 | 01:00:00 | true |
| 16:00:00 | 18:00:00 | false |
+-----------+----------+-----------+
3 rows in set (0.00 sec)
I am trying to calculate data from my database but first I've noticed strange behavior from the results I get, second, I have trouble making a request that take into account refills.
I have a table with :
Name - DateTime - content
I want to group by day the rows and select the difference of the number to have the consumption.
For example :
Name - DateTime - Content
Foo - 22-04-2018 6:00 - 120
Foo - 22-04-2018 10:00 - 119
Foo - 22-04-2018 16:00 - 118
The content has decreased, the result should be -2.
Output of my request = -2
Another example :
Name - DateTime - Content
Foo - 23-04-2018 6:00 - 50
Foo - 23-04-2018 10:00 - 90
Foo - 23-04-2018 16:00 - 120
Here we can notice that the number has increased. It means that instead of a consumption, we have refilled the reserve and the content has increased.
The result should be -70.
Output of my request : 30
My request :
SELECT day,
Abs(Sum(diffn)) AS totN
FROM (SELECT Date(datetime) AS day,
Max(content) - Min(content) AS diffN
FROM logs
WHERE NAME = 'Foo'
AND datetime >= '2018-04-22 00:00:00'
AND datetime <= '2018-04-23 00:00:00'
GROUP BY Date(datetime)) a
GROUP BY day;
But for the second example I have 30 as a result instead of 70, I don't know why...
I would like your help to change my request and take refills into account so that I get the results I want.
Thanks!
You need to determine the Prefix by comparing the highest and the lowest value, the time (hour) included. I'm using the 'CASE' function with two subqueries here.
Maybe you'll need to turn the year-month-day around, because I'm using the german datetime-format.
SET #datetime = '2018-04-22';
SELECT date(datetime) as day
,(CASE WHEN
(SELECT content FROM logs WHERE date(datetime) = #datetime ORDER BY datetime LIMIT 1)
>
(SELECT content FROM logs WHERE date(datetime) = #datetime ORDER BY datetime desc LIMIT 1)
THEN min(content) - max(content)
ELSE max(content) - min(content) END) as diffN
FROM logs
WHERE Name = 'Foo' AND date(datetime) = #datetime
GROUP BY day(datetime)
ORDER BY datetime
;
This should do the job:
SELECT day(datetime) as day, max(content) - min(content) as diffN
FROM logs
WHERE Name = 'Foo'
AND datetime >= '2018-04-23 00:00:00'
AND datetime <= '2018-04-24 00:00:00'
GROUP BY day(datetime)
Also, change the date filters it should be betweeen 23 and 24.
It might be that you need to establish the first and last datetime and their associated content. For example
drop table if exists t;
create table t (name varchar(3), dt datetime, content int);
insert into t values
('Foo' , '2018-04-22 06:00:00', 120),
('Foo' , '2018-04-22 10:00:00', 119),
('Foo' , '2018-04-22 16:00:00', 118),
('Foo' , '2018-04-23 06:00:00', 50),
('Foo' , '2018-04-23 10:00:00', 90),
('Foo' , '2018-04-23 16:00:00', 120);
select s.name,lastinday,firstinday,lastinday - firstinday
from
(
select name,dt, content lastinday
from t
where dt = (Select max(dt) from t t1 where t1.name = t.name and date(t1.dt) = date(t.dt))
) s
join
(
select name,dt, content firstinday
from t
where dt = (Select min(dt) from t t1 where t1.name = t.name and date(t1.dt) = date(t.dt))
) t
on t.name = s.name and date(t.dt) = date(s.dt);
+------+-----------+------------+------------------------+
| name | lastinday | firstinday | lastinday - firstinday |
+------+-----------+------------+------------------------+
| Foo | 118 | 120 | -2 |
| Foo | 120 | 50 | 70 |
+------+-----------+------------+------------------------+
2 rows in set (0.00 sec)
Why are you grouping it second time:
Ideally this should work:
SELECT Date(datetime) AS day,
Max(content) - Min(content) AS diffN
FROM logs
WHERE NAME = 'Foo'
AND datetime >= '2018-04-22 00:00:00'
AND datetime <= '2018-04-23 00:00:00'
GROUP BY Date(datetime)
Result of this query will contain only 2 rows - 1 for 22th and 1 for 23rd day. There is no need of grouping it again by day
mysql datetime select problem.
my table check_time:
count = 1
start = 23:57:45
end = 00:02:10
count = 2
start = 00:02:45
end = 00:07:10
i tried this query:
select count
from check_time
where start <= DATE_FORMAT(now(), '%H:%i:%s')
and end >= DATE_FORMAT(now(), '%H:%i:%s');
i want the now() = "23:57:45" between "00:02:10" select -> count = 1
not working on count 1 only.
but working perfectly other count 2~100..
sorry for my bad english.
A great deal depends on how you have actually defined the columns start and end. I have assumed they are "time" columns in the following.
Also note that to avoid the problem of using the server time which I could not control I have used #curtime but in your code you should use CURTIME() instead. See the demonstration demonstration at SQL Fiddle
CREATE TABLE check_time
(`count` int, `start` time, `end` time)
;
INSERT INTO check_time
(`count`, `start`, `end`)
VALUES
(1, '23:57:45', '00:02:10'),
(2, '00:02:45', '00:07:10')
;
Query 1:
set #curtime:= cast('23:57:45' as time)
select
*
, #curtime
from check_time
where (
(`start` < `end` and #curtime between `start` and `end`)
OR (`start` > `end` and
(#curtime between `start` and cast('24:00:00' as time) )
OR (#curtime between cast('00:00:00' as time) and `end` )
)
)
Results:
| count | start | end | #curtime |
|-------|----------|----------|----------|
| 1 | 23:57:45 | 00:02:10 | 23:57:45 |
Query 2:
set #curtime:= cast('00:02:45' as time)
select
*
, #curtime
from check_time
where (
(`start` < `end` and #curtime between `start` and `end`)
OR (`start` > `end` and
(#curtime between `start` and cast('24:00:00' as time) )
OR (#curtime between cast('00:00:00' as time) and `end` )
)
)
Results:
| count | start | end | #curtime |
|-------|----------|----------|----------|
| 2 | 00:02:45 | 00:07:10 | 00:02:45 |
I am not so into database and I have the following problem implementing a query. I am using MySql
I have a MeteoForecast table like this:
CREATE TABLE MeteoForecast (
id BigInt(20) NOT NULL AUTO_INCREMENT,
localization_id BigInt(20) NOT NULL,
seasonal_forecast_id BigInt(20),
meteo_warning_id BigInt(20),
start_date DateTime NOT NULL,
end_date DateTime NOT NULL,
min_temp Float,
max_temp Float,
icon_link VarChar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
PRIMARY KEY (
id
)
) ENGINE=InnoDB AUTO_INCREMENT=3 ROW_FORMAT=DYNAMIC DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
It contains meteo forecast information, something like this:
id localization_id start_date end_date min_temp max_temp icon_link
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 1 18/09/2017 06:00:00 18/09/2017 12:00:00 15 24 Mostly_Cloudy_Icon.png
2 1 18/09/2017 12:00:00 18/09/2017 18:00:00 15 24 Light_Rain.png
3 1 19/09/2017 06:00:00 19/09/2017 12:00:00 12 22 Mostly_Cloudy_Icon.png
4 1 19/09/2017 12:00:00 19/09/2017 18:00:00 13 16 Mostly_Cloudy_Icon.png
5 1 20/09/2017 06:00:00 20/09/2017 12:00:00 18 26 Light_Rain.png
6 1 20/09/2017 12:00:00 20/09/2017 18:00:00 17 25 Light_Rain.png
So, as you can see in the previous dataset, each record have a starting datetime and and ending datetime. This because I am collecting more forecast information in a specific day (it is based on time range, in the example for each day a record from 06:00 am to 12:00 and another record from 12:00 to 18:00 pm).
So, I created this simple query that extracts all the records in a specific range (in this case 2 days):
select * from MeteoForecast
where start_date between '2017-09-18 06:00:00' and '2017-09-20 06:00:00'
order by start_date desc;
I have to modify this query in the following way:
For each record retrieved by the previous query have to be added a new field named global_max_temp that is the maximum value of the max_temp field in the same day.
Doing an example related to the records related to theday having start_date value equal to 19/09/2017..., these are the records that I need to obtain:
id localization_id start_date end_date min_temp max_temp icon_link global_max_temp
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3 1 19/09/2017 06:00:00 19/09/2017 12:00:00 12 22 Mostly_Cloudy_Icon.png 22
4 1 19/09/2017 12:00:00 19/09/2017 18:00:00 13 16 Mostly_Cloudy_Icon.png 22
As you can see here the last field (inserted manually in this mock) is global_max_temp and in both records related to this day contains the value 22 because it is the maximum value of the max_temp field of all the records related to a specific day.
This is the query calculating these global_max_temp value:
select max(max_temp) from MeteoForecast
where start_date = '2017-09-19 06:00:00'
How can I add this feature to my original query?
Can you try something like this:
SELECT A.*, B.GLOBAL_MAX_TEMP
FROM (
select id, start_date, end_date, min_temp, max_temp
from MeteoForecast
where start_date between '2017-09-18 06:00:00' and '2017-09-20 06:00:00'
) A
INNER JOIN (SELECT date(start_date) AS date_only, MAX(max_temp) AS GLOBAL_MAX_TEMP
FROM MeteoForecast
WHERE start_date BETWEEN '2017-09-18 06:00:00' and '2017-09-20 06:00:00'
GROUP BY date(start_date)
) B ON date(A.start_date) = B.date_only
ORDER by start_date desc;