Has anyone seen the WHERE syntax below:
SELECT columns
FROM table
WHERE DATE(CONVERT_TZ(ifnull(expr1,expr2)".$dts.",'-05:00',table.timezone)) = CURDATE() + INTERVAL '10' DAY
The program sends notifications to a mailing list 10 days before a day of a sale (The number of days can change). I'm documenting queries and code written by a previous developer who left no notes and I'm stuck on the specific WHERE clause line.
I know that on the left of the equal sign, the query's interpreting that if expr1 is not null, select expr1, add daylight savings time ($dts), adjust the resulting value to a timezone (from EST to a specific timezone), then change the converted timezone to date format.
The right of the equal size takes the current date and adds 10 days to it.
So the reduced query kinda looks like (I think):
'2019-12-05' = CURDATE() + INTERVAL '10' DAY
Is left of the equal sign replacing the right or is it adding something to the right? Or am I just reading it wrong? What is it doing? Usually I see table columns set to specific values in the WHERE Clause, but not an explicit date set to something.
Related
This is a question from leetcode, using the second query I got the question wrong but could not identify why
SELECT
user_id,
max(time_stamp) as "last_stamp"
from
logins
where
year(time_stamp) = '2020'
group by
user_id
and
select
user_id,
max(time_stamp) as "last_stamp"
from
logins
where
time_stamp between '2020-01-01' and '2020-12-31'
group by
user_id
The first query uses a function on every row to extract the year (an integer) and compares that to a string. (It would be preferable to use an integer instead.) Whilst this may be sub-optimal, this query would accurately locate all rows that fall into the year 2020.
The second query could fail to locate all rows that fall into 2020. Here it is important to remember that days have a 24 hour duration, and that each day starts at midnight and concludes at midnight 24 hours later. That is; a day does have a start point (midnight) and an end-point (midnight+24 hours).
However a single date used in SQL code cannot be both the start-point and the end-point of the same day, so every date in SQL represents only the start-point. Also note here, that between does NOT magically change the second given date into "the end of that day" - it simply cannot (and does not) do that.
So, when you use time_stamp between '2020-01-01' and '2020-12-31' you need to think of it as meaning "from the start of 2020-01-01 up to and including the start of 2020-12-31". Hence, this excludes the 24 hours duration of 2020-12-31.
The safest way to deal with this is to NOT use between at all, instead write just a few characters more code which will be accurate regardless of the time precision used by any date/datetime/timestamp column:
where
time_stamp >= '2020-01-01' and time_stamp <'2021-01-01'
with the second date being "the start-point of the next day"
See answer to SQL "between" not inclusive
I have a form called FirstInLastOut which looks as the image below.
Based on Name or badge number I want to search between two dates.
I am using the following criteria on the query:
>=[Forms]![FirstInLastOut]![StartDateEntry] And <=[Forms]![FirstInLastOut]![EndDateEntry]
This is given me results that include other months as well. Please see the query report below.
So as you can see in the image the numbers of the dates are falling with the the parameter but getting other months as well.
How can I make it so it will only select the dates between the date ranges?
SELECT FistClockInRaw.Badgenumber, FistClockInRaw.name, FistClockInRaw.lastname, FistClockInRaw.MinOfCHECKTIME, FLastClockOutRaw.MaxOfCHECKTIME, [MaxOfCHECKTIME]-[MinOfCHECKTIME] AS TotalHours, FLastClockOutRaw.QDate, FistClockInRaw.MinOfQTime, FLastClockOutRaw.MaxOfQTime, RawCompleteQuery.CHECKTIME
FROM RawCompleteQuery, FLastClockOutRaw INNER JOIN FistClockInRaw ON (FLastClockOutRaw.Badgenumber = FistClockInRaw.Badgenumber) AND (FLastClockOutRaw.name = FistClockInRaw.name) AND (FLastClockOutRaw.QDate = FistClockInRaw.QDate)
WHERE (((FistClockInRaw.name)=[Forms]![FirstInLastOut]![FirstNameEntry]) AND ((RawCompleteQuery.CHECKTIME)>=[Forms]![FirstInLastOut]![StartDateEntry] And (RawCompleteQuery.CHECKTIME)<=[Forms]![FirstInLastOut]![EndDateEntry]));
is the Query
I assume that the forms fields StartDateEntry and EndDateEntry are bound to fields of type date.
I also assume that you are only interested to compare the date part of those form fields.
So try this condition instead to assure correct date interpreting:
WHERE FistClockInRaw.name=[Forms]![FirstInLastOut]![FirstNameEntry]
AND RawCompleteQuery.CHECKTIME >= Format([Forms]![FirstInLastOut]![StartDateEntry], "\#yyyy-mm-dd\#")
AND RawCompleteQuery.CHECKTIME <= Format([Forms]![FirstInLastOut]![EndDateEntry], "\#yyyy-mm-dd\#")
A remark:
Be aware that every date field/variable always contains a time part too!
So your current logic comparing EndDateEntry with <= can cause trouble, because you would only get results of the end date having time values of 00:00:00 in the field CHECKTIME.
If any record of CHECKTIME contains the requested end date and a time part bigger then 00:00:00, it is not in the result.
To avoid that, you should use < and add one day:
And RawCompleteQuery.CHECKTIME < Format([Forms]![FirstInLastOut]![EndDateEntry] + 1, "\#yyyy-mm-dd\#")
My table has the below mentioned timestamp
Outcome required: data between 1997 and 1999 morning times i.e. (12:00:01 to 11:59:59)
1997-09-22 18:02:38
1997-10-15 01:26:11
1997-11-03 02:42:40
1997-10-15 01:25:19
1999-10-15 01:25:19
1999-10-15 23:25:19
1998-03-12 20:15:12
1998-02-13 23:52:53
1997-09-23 23:26:01
2000-09-23 23:26:01
I am trying the below query but does not give the right outcome
SELECT * FROM r WHERE ts BETWEEN '1997-01-01 00:00:01' AND '1999-12-31 11:59:59'
I can find the outcome by extracting hours and minutes separately but is there a way where the query is a bit concise?
You need to extract date and time separately to fetch the needed data.
In MySql you can use DATE_FORMAT method to extract same.
Read more here: DATE_FORMAT(date, format)
Your query will be:
SELECT * FROM `r` WHERE DATE_FORMAT(ts, "%Y-%m-%d") BETWEEN '1997-01-01' AND '1999-12-31' AND DATE_FORMAT(date_time, "%H:%i:%s") BETWEEN '00:00:01' AND '11:59:59'
If your date is not in DateTime format then you need to convert your string/raw date to date time format using STR_TO_DATE method.
Read more here: STR_TO_DATE(date, format)
You may use STR_TO_DATE function :
SELECT *
FROM r
WHERE ts >= STR_TO_DATE('1997-01-01', '%Y-%m-%d')
AND ts < STR_TO_DATE('2000-01-01', '%Y-%m-%d')
P.S: ts <= '1999-12-31 11:59:59' implicitly means ts < '2000-01-01'
There's no way to specify particular hours of day within the range comparison that spans years. We'd need to add another predicate (condition) to narrow down the rows that match the range scan.
We can use DATE_FORMAT function to get hours, minutes and seconds (formatted with two digits each)
For example, based on the stated specification (only times between 00:00:01 and 11:59:59) we could add something like this:
AND DATE_FORMAT(r.ts,'%h:%i:%s') BETWEEN '00:00:01' AND '11:59:59'
But it seems really strange to be omitting the second right after midnight, and the second immediately before noon. (MySQL DATETIME can have resolution smaller than a second, up to six decimal digits.)
Personally, I'd identify "morning hours" as simply hour values between 0 and 11, like this:
AND DATE_FORMAT(r.ts,'%h') BETWEEN '00' AND '11'
That will include "morning times" before 12:01 AM and after 11:59 AM. For example, these times would be included by this condition, but be omitted by the first example condition:
00:00:00.555
11:59:59.023
The specification isn't entirely clear... determining whether these times should be included or excluded would help clarify the specification. I suspect the statement of the specification is somewhat jarbled, and we really want all "morning times" between midnight and noon.
SELECT r.*
FROM r
WHERE r.ts >= '1997-01-01'
AND r.ts < '2000-01-01'
AND DATE_FORMAT(r.ts,'%h) BETWEEN '00' AND '11'
But it really depends on the definition of "morning hours", whether that first second after midnight is included or excluded.
I have a mysql table which stores users' availability, stored in 'start' and 'end' columns as date fields.
I have a form where other users can search through the 'availabilty' with various periods like, today, tomorrow and next week . I'm trying to figure out how to construct the query to get all the rows for users who are available 'next month'.
The 'start' values maybe from today and the 'end' value might might be three months away but if next month falls between 'start' and 'end' then I would want that row returned.
The nearest I can get is with the query below but that just returns rows where 'start' falls within next month. Many thanks,
sql= "SELECT * FROM mytable WHERE start BETWEEN DATE_SUB(LAST_DAY(DATE_ADD(NOW(), INTERVAL 1 MONTH)),INTERVAL DAY(LAST_DAY(DATE_ADD(NOW(), INTERVAL 1 MONTH)))-1 DAY) AND LAST_DAY(DATE_ADD(NOW(), INTERVAL 1 MONTH))";
As you are interested in anything that happens in the full month following the current date you could try something like this:
SELECT * FROM mytable WHERE
FLOOR(start/100000000)<=FLOOR(NOW()/100000000)+1 AND
FLOOR( end/100000000)>=FLOOR(NOW()/100000000)+1
This query make use of the fact that datetime values are stored in MySql internally as a number like
SELECT now()+0
--> 20150906130640
where the digits 09 refer to the current month. FLOOR(NOW()/100000000) filters out the first digits of the number (in this case:201509). The WHERE conditions now simply test whether the start date is anywhere before the end of the next month and the end date is at least in or after the period of the next month.
(In my version I purposely left out the condition that start needs to be "after today", since a period that has started earlier seems in my eyes still applicable for your described purpose. If, however, you wanted that condition included too you could simply add an AND start > now() at the end of your WHERE clause.)
Edit
As your SQLfiddle is set-up with a date instead of a (as I was assuming) datetime column your dates will be represented differently in mumeric format like 20150907 and a simple division by 100 will now get you the desired month-number for comparison (201509):
SELECT * FROM mytable WHERE
FLOOR(start/100)<=FLOOR(NOW()/100000000)+1 AND
FLOOR( end/100)>=FLOOR(NOW()/100000000)+1
The number returned by NOW() is still a 14-digit figure and needs to be divided by 100000000. See your updated fiddle here: SQLfiddle
I also added another record ('Charlie') which does not fulfill your requirements.
Update
To better accommodate change-of-year scenarios I updated my SqlFiddle. The where clause is now based on 12*YEAR(..)+MONTH(..) type functions.
If I have MySQL query like this, summing word frequencies per week:
SELECT
SUM(`city`),
SUM(`officers`),
SUM(`uk`),
SUM(`wednesday`),
DATE_FORMAT(`dateTime`, '%d/%m/%Y')
FROM myTable
WHERE dateTime BETWEEN '2011-09-28 18:00:00' AND '2011-10-29 18:59:00'
GROUP BY WEEK(dateTime)
The results given by MySQL take the first value of column dateTime, in this case 28/09/2011 which happens to be a Saturday.
Is it possible to adjust the query in MySQL to show the date upon which the week commences, even if there is no data available, so that for the above, 2011-09-28 would be replaced with 2011/09/26 instead? That is, the date of the start of the week, being a Monday. Or would it be better to adjust the dates programmatically after the query has run?
The dateTime column is in format 2011/10/02 12:05:00
It is possible to do it in SQL but it would be better to do it in your program code as it would be more efficient and easier. Also, while MySQL accepts your query, it doesn't quite make sense - you have DATE_FORMAT(dateTime, '%d/%m/%Y') in select's field list while you group by WEEK(dateTime). This means that the DB engine has to select random date from current group (week) for each row. Ie consider you have records for 27.09.2011, 28.09.2011 and 29.09.2011 - they all fall onto same week, so in the final resultset only one row is generated for those three records. Now which date out of those three should be picked for the DATE_FORMAT() call? Answer would be somewhat simpler if there is ORDER BY in the query but it still doesn't quite make sense to use fields/expressions in the field list which aren't in GROUP BY or which aren't aggregates. You should really return the week number in the select list (instead of DATE_FORMAT call) and then in your code calculate the start and end dates from it.