http://upic.me/i/hq/capture.png
http://upic.me/i/3g/capture.png
I have the table that divide datetime to single field and set these field to index.
i would to use where clause in date range ex. between 2010/06/21 to 2011/05/15
I try to use
where concat_ws('-',year,month,day) between '2010/06/21' and '2011/05/15'
it's work because I use concat function to adjust these field like ordinary datetime
but it not use index and query slowly.This table has 3 million record
if would to use index I try to this query
where
year = '2011'
and month between 05 and 06
and day between 21 and 15
It almost work but in last line
day between 21 and 15
I can't use this condition
I try to solve this problem but I can't find it and change structer table
I'm looking for answer
thank you
Now I can OR operation for query thank for your answer
In another case if would to find 2009/08/20 to 2011/04/15 It's use longer query and make confusion.Has someone got idea?
If it's a datestamp type, you can just use the where/between clause directly. I would consider switching to that, it's quite faster than a varchar with a custom date format.
WHERE yourdate BETWEEN "2011-05-01" AND "2011-06-15"
Although checking ranges may work for single months, you will find if you're querying between several months to have some margin of error because, if you think about it, you're selecting more than you may necessarily want. Using Datestamp will fix performance and usability issues arising from storing the date in a custom varchar.
Here are the two queries to convert your times around if you're interested:
ALTER TABLE `yourtable` ADD `newdate` DATE NOT NULL;
UPDATE `yourtable` SET `newdate` = STR_TO_DATE(`olddate`, '%Y/%m/%d');
Just change "yourtable", "newdate", and "olddate" to your table's name, the new date column name, and the old datestamp column names respectively.
If you can't change the table structure, you could use something like the following:
WHERE year = '2011'
AND ((month = '05' AND day >= 21) OR (month = '06' AND day <= '15'))
(At least, I think that query does what you want in your specific case. But for e.g. a longer span of time, you'd have to think about the query again, and I suspect queries like this could become a pain to maintain)
UPDATE for the updated requirement
The principle remains the same, only the query becomes more complex. For the range of 2009/08/20 to 2011/04/15 it might look like this:
WHERE year = '2009' AND (month = '08' AND day >= '20' OR month BETWEEN '09' AND '12')
OR year = '2010'
OR year = '2011' AND (month BETWEEN '01' AND '03' OR month = '04' AND day <= '15')
where year = 2011
and (month between 5 and 6) and (day > 20 or day < 16)
You where seperating days and month whereas you must keep them together
parentheses must be set ...
Mike
It is important that you use OR otherwise it is nonsense
Related
I have updated the value of the SAD_PB_CAS_STATDT field equal to sysdate which is the date today. The problem now is when i query something with that SAD_PB_CAS_STATDT = sysdate, it does not return anything.
see my sql code below:
SELECT EMPLID, ACAD_CAREER, STDNT_CAR_NBR, ADM_APPL_NBR, APPL_PROG_NBR,
SAD_PB_CAS_STATUS, SAD_PB_CAS_STATDT
FROM PS_SAD_PB_CAS
WHERE SAD_PB_CAS_STATUS IN ('ASG', 'USD')
AND SAD_PB_CAS_STATDT = sysdate;
I'm guessing it has something to do with the return type of sysdate? does it return something with date and time? any help would be appreciated for me to be able to pull the query with sysdate in the conditions.
As others have mentioned, always check the documentation (including Stack Overflow) before you post a question. There are several ways to make your query work, but I would recommend the following WHERE clause:
WHERE
SAD_PB_CAS_STATUS IN ('ASG', 'USD') AND
SAD_PB_CAS_STATDT >= CURDATE() AND -- today at midnight
SAD_PB_CAS_STATDT < CURDATE() + INTERVAL 1 DAY; -- tomorrow at midnight
The reason why this approach is favored over casting your SAD_PB_CAS_STADT column to a date only, is that the above allows an index to be used on the column, if it exists.
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.
Had a bit unintuitive case right now with MySQL:
the query contains where clause with comparison: WHERE t.date = '2016-12-31' (t.date-s datatype is DATE(!)).. And it returns no records on execution. But the query: WHERE t.date > '2016-12-31' - returns the records with date equals '2016-12-31' among other records! The record for 2016-12-31 also showed up in case I've used BETWEEN '20161231' AND '20170101'. Tried formattings, type changes - nothing helped. After some time spent on searching for cause I did the following: updated the record's date column manually, SETting it to '2016-12-31'. After this action WHERE t.date = '2016-12-31' started to work as expected.
Probably I'm missing something, wondering what can cause such behavior.
Update
date is DATE, not DATETIME
After doing manual update I can't reproduce the mentioned behavior again: now any type of comparison(=, DATE(..)=, STRCMP) - works as it should!
Update 2
For 2016-11-30 and 2016-09-30(end of months!) found the same behavior! Won't update the record manually for now to test the suggestions I get here.
Update 3
I've also run OPTIMIZE TABLE on the table with that date column to rebuild indexes for elimination any problems with corruption.
Update 4
Here is more:
if I check HEX values for the date field for incorrect fields(end of month) I get wrong values!
SELECT HEX(t.date) FROM table t WHERE t.date BETWEEN DATE('20160930') AND DATE('20161001');
Returns:
323031362D31302D3030
323031362D31302D3031
SELECT HEX(DATE('20160930'));
Returns:
323031362D30392D3330
And 323031362D30392D3330 != 323031362D31302D3030
SELECT X'323031362D31302D3030';
And it returns:
2016-10-00, NOT 2016-09-30!
For the value that I've updated manually - HEX is same.
But what can cause such difference?
Try forcing the format using
WHERE date(t.date) = '2016-12-31'
or
WHERE date(t.date) = str_to_date( '2016-12-31', '%Y-%m-%d')
or based on your test
WHERE date(t.date) = str_to_date( '20161231', '%Y%m%d')
After some investigation I've found the problem and its not related directly to the date comparison in MySQL. I'll post it here in case anyone is stuck at such case.
I've found that the problem was with selecting results in IDE (in my case DataGrip): the value for date field in database was 2016-10-00 and select was returning 2016-09-30! That was confusing.. But after the 00 DAY was found - it was relatively easy to find the cause of it: CURDATE() - 1 (in my case there should have been: CURDATE() - INTERVAL 1 DAY). Don't ever use date related functionality without specific functions like INTERVAL!!
Thanks to everyone who supported the question, sorry for confusion, I was confused too and found the answer only after several steps.
I have attendance data for employees stored in the table attendance with the following column names:
emp_id (employee ID)
date
type (leave, absent, etc.)
(there are others but I'm omitting them for the sake of simplicity)
My objective is to retrieve all dates of the given month on which the employee was on leave (type = 'Leave') and the last leave taken in the last month, if any.
It's easy to do it using two queries (I'm using PHP to get process the data), but is there any way this can be done in a single query?
I'm answering my own question so as to close it. As #bpgergo pointed out in the comments, UNION will do the trick here.
SELECT * FROM table_name
WHERE type="Leave" AND
date <= (CURRENT_DATE() - 30)
Select the fields, etc you want then se a combined where clause using mysql's CURRENT_DATE() function. I subtracted 30 for 30 days in a month.
If date is a date column, this will return everyone who left 1 month or longer ago.
Edit:
If you want a specific date, change the 2nd month like this:
date <= (date_number - 30)
im having a problem where i cant think of a solution, maybe im having a bad table-structure or i just dont know enough about mysql select commands to think of a good solution. Maybe you can help me out:
So i got a table that has a Column with the Date-format (yyyy-mm-dd) i wanted to select all upcoming dates so i did:
SELECT * WHERE date >= now.
This worked kinda well but i also got "dates" where only the year is entered (2014-00-00) i also wanted to select these but "now" is already bigger so i made another column with the year only and if the month, date or both arent known i will use 0000-00-00 and the Column "year" now i could select like this:
SELECT * WHERE date >= now AND year >=now(year)
Now all entrys with 0000-00-00 wont be selected. If i use OR the entrys from last year will be shown.
So thats my problem, is there any way i can change my table so i can have entries with only the year or only year and month and of course all together? I already considered get rid of the date-format and use simple INT with seperated columns for year, month and date. But i think i will have the same problem.
Sometimes i just want to do a capsuled select like
SELECT *
WHERE (date >= now AND year >= now(year))
OR date == "0000-00-00" (i know that this doesnt work)
If I understood your problem correctly, you could use this request:
WHERE (date >= now OR year > now(year))
There is probably a simpler way though, that would preserve your design, like initializing at January 1st (01-01) instead of 00-00
I think you can use this code:
$_SESSION['month'] = //set here your selected month
$_SESSION['year'] = //set here your selected year
SELECT * FROM table WHERE DATEPART(m,date) >= '".$_SESSION['month']."' AND DATEPART(yyyy,year) >= '".$_SESSION['year']."' AND date <> '0000-00-00'
Change your table structure format. Actually just allow for that field to have null value when not entered. By default it will be null then. You shouldn't be storing 0000-00-00 as a value for Date type field. I would rather leave it as null , or as suggested in some of previous answers, initialize it with some other date. It would be much easier to manipulate with database then.
the problem is that half of you write is not MySQL and your database schema is terrible...
You have the following problems:
column data date does not have the date data type.
To fix it, you need to add a cast to the select statement eg. cast(datecolumn as date)
select * from table where cast(datecolumn as date) >= '2014-01-10';
the way to use now date is using the now function.
select now(), date(now());
result> 2014-01-10 11:11:36, 2014-01-10
select * from table where cast(datecolumn as date) >= date(now());
Because your datecolumn is not a date (2014-00-00 is not a valid date), you need to use string manipulation to extract the year.
select substring('2014-01-01', 1,4)
result> 2014
select * from table where substring(datecolumn, 1,4) = year(now());
The comparassion operator is = and not ==
the select statement syntax looks like this (pay attention because you are missing the table in your statement)
select * from [Table] where [column] = condition ...
You probably need or instead of ands, therefore your query should look like this:
select * from FooTable where
cast(datecolumn as date) >= date(now())
or substring(datecolumn, 1,4) >= year(now())
or datecolumn = '0000-00-00'
You should use something like phpmyAdmin or mySQL workbench to test your sql queries before try to use them on php, java or whatever is your programing language.