I have a table to store data for car rental purposes (reservations awaiting response). The is a field called 'initiated_datime' (INT, 10) where the initiated datime of the reservation is stored (I already know that INT 10 is not the most efficient way, 2038 etc.).
I would like to view reservations awaiting response more than 24 hours for further reporting...
The following examples work for me
SELECT * FROM rentals WHERE rental_flag = 1 AND '".$cur_datetime_unixtime."' >(initiated_datime + 86400) ... WHERE $cur_datetime_unixtime is created in php
AND
SELECT * FROM rentals WHERE rental_flag = 1 AND unix_timestamp(now()) > (initiated_datime + 86400)
is there any way to change (initiated_datime + 86400) with a more efficient code? like: unix_timestamp(initiated_datime + 1 day interval)?
Thank you in advance!
Not in the general case; but in this instance, that inequality is equivalent to:
SELECT * FROM rentals WHERE rental_flag = 1
AND unix_timestamp(now() - INTERVAL 1 DAY) > initiated_datime
The most efficient way to fix this is to change your columns to a datetime. You can than easily use date/time functions to manipulate your filter.
Related
I have a table that contains sensor data with a column timestamp that holds the unix timestamp of the time the sensor measurement has been taken.
Now I would like to SELECT all measurements within a certain date/time range with a specific time step.
I figured the first part out myself like you can see in my posted code snippet below.
// With $date_start and $date_stop in the format: '2010-10-01 12:00:00'
$result = mysqli_query($connection, "SELECT sensor_1
FROM sensor_table
WHERE timestamp >= UNIX_TIMESTAMP($date_start)
AND timestamp < UNIX_TIMESTAMP($date_stop)
ORDER BY timestamp");
Now is there a convenient way in MySQL to include a time step size into the same SELECT query?
My table contains thousands of measurements over months with one measurement taken every 5 seconds.
Now let's say I would like to SELECT measurements in between 2010-10-01 12:00:00 and 2010-10-02 12:00:00 but in this date/time range only SELECT one measurement every 10 minutes? (as my table contains measurements taken every 5 seconds).
Any smart ideas how to solve this in a single query?
(also other ideas are very welcome :))
Since you take one measurement every 5 seconds, the difference between $date_start and the first matching measurement cannot be greater than 4. We then take one entry every 600 seconds (allowing for some discrepancy from clock to clock...)
SELECT sensor_1
FROM sensor_table
WHERE timestamp >= UNIX_TIMESTAMP($date_start)
AND
timestamp < UNIX_TIMESTAMP($date_stop)
AND
((timestamp - UNIX_TIMESTAMP($date_start)) % 600) BETWEEN 0 AND 4
ORDER BY timestamp;
It is not elegant, but you can do:
SELECT s.sensor_1
FROM sensor_table s
WHERE s.timestamp >= UNIX_TIMESTAMP($date_start) AND
s.timestamp < UNIX_TIMESTAMP($date_stop) AND
s.timestamp = (SELECT MIN(s2.timestamp)
FROM sensor_table s2
WHERE s2.timestamp >= 60 * 10 * FLOOR(UNIX_TIMESTAMP(s.timestamp) / (60 * 10)) AND
s2.timestamp < s2.timestamp >= 60 * 10 * (1 + FLOOR(UNIX_TIMESTAMP(s.timestamp) / (60 * 10)))
)
ORDER BY timestamp;
This selects the first in each 10 minute period.
I think that you could use a simple cursor in plSQL
CREATE TABLE StoreValuesId
(
valueId int primary key;
)
CREATE OR REPLACE procedure_store[date_start date,date_stop date]
DECLARE date_startUpdated date , date_stopUpdated date , date_diff TIME(7) = '00:10:00'
IS
BEGIN
SELECT date_start INTO date_startUpdated;
SELECT date_stop INTO date_stopUpdated;
IF timestamp BETWEEN date_start and date_stop then
INSERT INTO StoreValuesId values(timestamp)
date_startUpdated=DATEADD(SECOND, DATEDIFF(SECOND, 0, date_diff), date_startUpdated);
date_stopUpdated=DATEADD(SECOND, DATEDIFF(SECOND, 0, date_diff), date_stopUpdated);
END IF
COMMIT;
END
Then again the syntax might be wrong but I hope you'll get the idea (haven't played with sql in a while)
There is an existing Dates dimension table which I need to query.
The structure looks like this:
ID | Year | Month | Day
How can I query for a range of dates?
Example: I want to get the dates from 03/02/2018 to 03/02/2020
I've tried the following:
SELECT *
from Dates dateDim
where (dateDim.Year >= 2018 and dateDim.Month >= 2 and dateDim.Day >= 3)
and (dateDim.Year <= 2020 and dateDim.Month <= 2 and dateDim.Day <= 3);
With standard SQL you can compare tuples (=multiple columns) with a single expression:
select *
from dates
where (year, month, day) >= (2018,2,3) and (year, month, day) <= (2020, 1, 3);
Not all DBMS products support that however, but you didn't mention a specific DBMS product and the tag sql refers to "standard SQL".
Online example: https://rextester.com/NTZH63192
But you should really consider change that to a single column of type DATE.
SELECT *
from Dates dateDim
where dateDim.Year * 10000 + dateDim.Month * 100 + dateDim.Day
between 20180203 and 20200203
As has been commented, change your Dates table so it actually holds DATE types. You can easily retrieve the year/month/day from a date. Most typical operations that involve your date table will involve conversion to a date, then some operation (like adding days/months etc) then converting back. If you store these thigns as dates you save that first step. Over the life of the DB storing it properly will save you more than whatever spurious reason they're stored like this is intended to help with
You could also do this mathematically (or stringily):
SELECT * FROM dates WHERE year * 10000 + month * 100 + day BETWEEN 20180203 and 20200103
But it's a bit of a lame hack compared to storing the data properly in the first place
If you are using MS-SQL, I would recommend, if Year, Month and Day are INT's, converting these to a DateTime and you have much more control, something like this should suffice:
SELECT
*
FROM
Dates.dateDim AS foo
WHERE
CAST(CAST(foo.Year AS varchar) + '-' + CAST(foo.Month AS varchar) + '-' + CAST(foo.Day AS varchar) AS DATETIME) BETWEEN '2018/02/03' AND '2020/02/03'
Declare
#date1 date = '2015-12-01'
,#date2 date = '2015-12-30'
BEGIN
Declare #date_u char = Month(#date1)
,#date_v char = Month(#date2)
Select
STD.StoreNo As StoreNo
,CheckDate as Date
,ProductBarCode as ProductBarCode
,SUM( StocktakingQty)AS ProducQty
From StockTakingDetail STD
Inner Join
(Select StoreNo,CheckNo,CheckDate
From StockTakingMain SM )StocktakingMain
On STD.CheckNo =StockTakingMain.CheckNo
where year(CheckDate) between #date_u and #date_v
group By STD.StoreNo,STD.ProductBarCode,CheckDate
End
Actually, I want to show daily inventory, but once a month only.
They use to take inventory in the warehouse. I cannot able to fill dates gap without the data. So, I planned to use month and year only to get data . But, I can't be able to find a way how to take input parameter only month and year from date.
Can anyone help?
Do you want your where clause to look like this?
where year(CheckDate) * 100 + month(CheckDate) between year(#date1) * 100 + month(#date1) and
year(#date2) * 100 + month(#date2)
If so, I would really go fo:
where CheckDate >= date_sub(#date1, interval 1 - day(#date1)) and
CheckDate < date_add(date_sub(#date2, interval 1 - day(#date2)), interval 1 month)
In a table I have a column called 'service_time' which is the start date of a service, and another column 'times_year' which is how many times per year the service shall be done.
The problem I have is how I should select the rows when -> (thisMonth == service_time (month)) OR (thisMonth == service_time (month) + 12/times_year)
The tricky part that I cannot solve is how should I do this if the 'times_year' is a value between 1-4? Without making 4 different OR's??
So should it be something of a loop decided by the 'times_year' instead of doing a OR query to check all 4 OR's every single time even if the 'times_year' isn't 4?
UPDATE:
Well I need help how to do a loop in the sql query statement wich will only select if the 'month' is correct, so basiclly now its the '08' and if the service_time is set to 2015-03-01 (day doesnt matter) it shall do a check with the times_year to check if 2015-03-01 shall be having a service > 2015-03 + 12/4(as an example) then 2015-06, 2015-09, 2015-12, 2016-03 Then no dont select and so on...
I could do this in PHP but it will not be efficent in the longer term
Hopefully, you don't have times_year values like 5, 11, and so forth. That will get a little nasty to work out. Values like 1,2,3,4,6,12 are good.
You can determine the next service time after the start time like this in MySQL
service_time + INTERVAL (12 DIV times_year) MONTH
Similarly, the third service time after the start time will work like this.
service_time + INTERVAL 3*(12 DIV times_year) MONTH
Maybe your business rules call for service to be due on or before the last calendar day of each month. You can display that like so.
LAST_DAY(service_time + INTERVAL 3*(12 DIV times_year) MONTH)
Finally, you may wish to display the next service due date after today (after CURDATE()) How do you do that?
First, it has been this many months since the first service time:
TIMESTAMPDIFF(MONTH, service_time, CURDATE())
Next, you want to know how many service intervals that covers. Easy:
times_year * TIMESTAMPDIFF(MONTH, service_time, CURDATE()) / 12.0
Next, you want the next highest service interval number:
CEIL(times_year * TIMESTAMPDIFF(MONTH, CURDATE(), service_time) / 12.0)
Finally, plug that into the next-service-time function:
service_time + INTERVAL
CEIL(times_year * TIMESTAMPDIFF(MONTH, service_time, CURDATE()) / 12.0)*
(12 DIV times_year) MONTH
It's a long formula, but it works.
Finally, you can use this WHERE clause to find out all the services due before the end of the present month.
WHERE LAST_DAY(service_time + INTERVAL
CEIL(times_year * TIMESTAMPDIFF(MONTH, service_time, CURDATE()) / 12.0)*
(12 DIV times_year) MONTH) <= LAST_DAY(CURDATE())
I have a cron that runs some php with some mysql just after midnight everyday. I want to take all registered users (to my website) and send them a reminder and copy of the newsletter. However I want to do this every 30 days from their registration.
I have thought as far as this:
SELECT * FROM users
WHERE DATE(DT_stamp) = DATE(NOW() - INTERVAL 30 DAY
But this will only work for 30 days after they have registered, not 60 and 90.
Effectively I want:
Where days since registration is divisible by 30
That way every 30 days that user will get picked up in the sql.
Can someone help me formulate this WHERE clause, I am struggling with mysql where day(date1-date2) divisible 30
The DATEDIFF function returns the difference between two dates in days, ignoring the time:
SELECT * FROM users
WHERE DATEDIFF(DT_stamp, NOW()) % 30 = 0
or the other way round...
SELECT * FROM users WHERE MOD(DATEDIFF(NOW(),registration_date),30) = 0;
Use SQL modulo function MOD():
SELECT * FROM users
WHERE MOD( DATE(DT_stamp) - DATE(NOW()), 30) = 0
In mysql, you can also use the % operator, which does the same thing:
SELECT * FROM users
WHERE (DATE(DT_stamp) - DATE(NOW()) % 30 = 0
Just an addition (not that nine years had passed :)
If you want to skip today's date you should add
AND DATEDIFF(NOW(), DT_stamp) != 0;
making it
SELECT * FROM users WHERE MOD(DATEDIFF(NOW(), DT_stamp), 30) = 0 AND DATEDIFF(NOW(), DT_stamp) != 0;