I generally use datetime field to store created_time updated time of data within an application.
But now i have come across a database table where they have kept date and time separate fields in table.
So what are the schema in which two of these should be used and why?
What are pros and cons attached with using of two?
There is a huge difference in performance when using DATE field above DATETIME field. I have a table with more then 4.000.000 records and for testing purposes I added 2 fields with both their own index. One using DATETIME and the other field using DATE.
I disabled MySQL query cache to be able to test properly and looped over the same query for 1000x:
SELECT * FROM `logs` WHERE `dt` BETWEEN '2015-04-01' AND '2015-05-01' LIMIT 10000,10;
DATETIME INDEX:
197.564 seconds.
SELECT * FROM `logs` WHERE `d` BETWEEN '2015-04-01' AND '2015-05-01' LIMIT 10000,10;
DATE INDEX:
107.577 seconds.
Using a date indexed field has a performance improvement of: 45.55%!!
So I would say if you are expecting a lot of data in your table please consider in separating the date from the time with their own index.
I tend to think there are basically no advantages to storing the date and time in separate fields. MySQL offers very convenient functions for extracting the date and time parts of a datetime value.
Okay. There can be some efficiency reasons. In MySQL, you can put separate indexes on the fields. So, if you want to search for particular times, for instance, then a query that counts by hours of the day (for instance) can use an index on the time field. An index on a datetime field would not be used in this case. A separate date field might make it easier to write a query that will use the date index, but, strictly speaking, a datetime should also work.
The one time where I've seen dates and times stored separately is in a trading system. In this case, the trade has a valuation date. The valuation time is something like "NY Open" or "London Close" -- this is not a real time value. It is a description of the time of day used for valuation.
The tricky part is when you have to do date arithmetic on a time value and you do not want a date portion coming into the mix. Ex:
myapptdate = 2014-01-02 09:00:00
Select such and such where myapptdate between 2014-01-02 07:00:00 and 2014-01-02 13:00:00
1900-01-02 07:00:00
2014-01-02 07:00:00
One difference I found is using BETWEEN for dates with non-zero time.
Imagine a search with "between dates" filter. Standard user's expectation is it will return records from the end day as well, so using DATETIME you have to always add an extra day for the BETWEEN to work as expected, while using DATE you only pass what user entered, with no extra logic needed.
So query
SELECT * FROM mytable WHERE mydate BETWEEN '2020-06-24' AND '2020-06-25'
will return a record for 2020-06-25 16:30:00, while query:
SELECT * FROM mytable WHERE mydatetime BETWEEN '2020-06-24' AND '2020-06-25'
won't - you'd have to add an extra day:
SELECT * FROM mytable WHERE mydatetime BETWEEN '2020-06-24' AND '2020-06-26'
But as victor diaz mentioned, doing datetime calculations with date+time would be a super inefficient nightmare and far worse, than just adding a day to the second datetime. Therefore I'd only use DATE if the time is irrelevant, or as a "cache" for speeding queries up for date lookups (see Elwin's answer).
Related
I have a weird problem in mysql!
my query is
SELECT * FROM aa WHERE problemTime>= '2016/03/20' AND problemTime<= '2016/04/20'
the result of this query is nothing , but when I change the first time to 2016/03/19 or 2016/03/21 I have the following result! I mean these queries
SELECT * FROM aa WHERE problemTime>= '2016/03/21' AND problemTime<= '2016/04/20'
or
SELECT * FROM aa WHERE problemTime>= '2016/03/19' AND problemTime<= '2016/04/20'
the result in both time ( 19th and 21th) is
but when I use 20th the result is noting
my main table is
I change the format of time from 2016/03/20 to 2016-03-20 ( I mean change / to - ) but it doesn't have change too!
whats the problem?
You should really be running a query like this if your problemTime column is datetime type:
SELECT * FROM aa
WHERE
problemTime>= str_to_date('2016/03/20', '%Y/%m/%d') AND
problemTime <= str_to_date('2016/04/20', '%Y/%m/%d')
Don't rely on implicit conversions between string and date.. leave your table data alone and ensure you explicitly convert your where clause parameters to the same data type as in the table. Also remember that a date "without" a time is actually midnight on the day in question, and midnight is like zero, it's the first thing that happens on any given day. A time of 6am on a given date, is after midnight, so a query that asks for dates less than or equal to midnight on a particular date means the 6am date will be excluded
This is general good DB practice; do not convert table data where possible, because it can cause huge performance hits and wrong results
Your column "problemTime" have date with time. Do not convert table data, change your where clause (add time).
SELECT * FROM aa WHERE problemTime>= '2016/03/20 00:00:00' AND problemTime<= '2016/04/20 23:59:59'
Try this as per SQl Server.
SELECT * FROM aa
WHERe cast(problemTime AS date) between '2016/03/21' AND '2016/04/20'
I have to perform a query on a MySQL database.
I have a table with records, have a column called "date" (the date type), and a column called "time" (type. Integer is stored by multiplying the time of day by 60. eg 8 am is stored as 480).
Unfortunately, the format of this table can not be modified.
My table stores attentions of doctors on call. The doctors on duty working in two shifts: from 8-20, and 20-8.
I need to know the amount of attention for every doctor.
My query must be filtered by date range and shift.
The problem is that, in the case of doctors working at the turn of 20-8, I have to consider a change of day. (sorry for my bad English).
What I have done is this, this would be an example to date of yesterday, and doctors shift 20-8.
SELECT * FROM attentions WHERE (date >= '2015-07-23' and time >=1200) and (date <= '2015-07-24' and time <480)
the query does not work at all.
Supposing the date field is called: 'a_date' with format 'yyyy-mm-ss' and the time field is a number, the query should be:
SELECT * FROM attentions WHERE (date(a_date) >= '2015-07-23' and time >=1200) and (date(a_date) <= '2015-07-24' and time <480)
Can you check using between?
SELECT * FROM attentions WHERE date between '2015-07-23' and '2015-07-24' and time between 1200 and 480
I think you can also use this -
SELECT * FROM ***** where CREATED_DATETIME between '2015-03-12 00:00:00' and '2015-05-11 00:00:00';
I have a problem saving 'contable dates' because every month on this way has 30 days each. I need to save a element (2014-02-30) using a type date-like (not a varchar/text/blob/etc) to save this because in this project we need that. Is it possible?
Saving such a DATE "value" in a DATE or DATETIME column is possible using the sql_mode ALLOW_INVALID_DATES and no strict mode:
ALLOW_INVALID_DATES
Do not perform full checking of dates. Check only that the month is in
the range from 1 to 12 and the day is in the range from 1 to 31. This
is very convenient for Web applications where you obtain year, month,
and day in three different fields and you want to store exactly what
the user inserted (without date validation). This mode applies to DATE
and DATETIME columns. It does not apply TIMESTAMP columns, which
always require a valid date.
So checking the date for an allowed contable date could be done with triggers, since there's no other check too. I assume that for this application the 31th of each month would be an invalid date.
Example:
CREATE TABLE example (
contable_date DATE NOT NULL
) ENGINE=INNODB;
-- set the sql_mode (here for the session)
SET ##SESSION.sql_mode = 'ALLOW_INVALID_DATES';
INSERT INTO example (contable_date) VALUES ("2014-02-30");
SELECT
DAY(contable_date) as cday,
MONTH(contable_date) as cmonth,
TIMESTAMPDIFF(DAY, contable_date, '2014-03-30') as cdiff
FROM
example;
Result:
cday cmonth cdiff
-------------------
30 2 28
Demo
Using MySQL Workbench I get with
SELECT contable_date FROM example
following result:
contable_date
-------------
2014-02-30
but this doesn't work at sqlfiddle.com.
I wouldn't recommend this though, especially because one's not able to use strict SQL mode. One should consider the effect on the date and time functions too.
I have the following mysql table:
tasks:
=====================
tid
status
desc
duedate
And i have the following records in that table:
records
===========================
1
active
Test description
08/15/2014
2
active
Another description
08/31/204
I am trying to get the days that there is a task for, in that particular month. I have the following query but when i run it it gets both records but "day" is null on both of them for some reason. Can someone please help me with this.
MYSQL QUERY
====================
SELECT DATE_FORMAT(due_date,'%d') AS day FROM tasks WHERE due_date BETWEEN '08/01/2014' AND '08/31/2014'
Try:
SELECT DAY(due_date) AS day
FROM tasks
WHERE due_date >= '2014-08'
AND due_date < '2014-09';
DAY() is a better function for what you want and I prefer using >= and < than BETWEEN for date comparisons, as it allows you to specify precise ranges more easily. Here, for example, you don't need to know the number of days in the month.
I have also used the default date format, which is preferable. If you need the, in my opinion, cray American date format, use DATE_FORMAT() in your SELECT.
This will only work with DATE, DATETIME and TIMESTAMP columns, which is how your due_date should be stored, preferably DATE.
UPDATE
To convert the VARCHAR column to DATE run:
UPDATE tasks SET due_date=STR_TO_DATE(due_date,'%m/%d/%Y')
Then change the type. Also remember to change your INSERT statements to use the default format.
You've got to convert those "date" strings to proper date values with STR_TO_DATE:
SELECT
DAY(STR_TO_DATE(due_date,'%m/%d/%Y')) AS day
FROM tasks
WHERE
STR_TO_DATE(due_date, '%m/%d/%Y')
BETWEEN STR_TO_DATE('08/01/2014' '%m/%d/%Y')
AND STR_TO_DATE('08/31/2014', '%m/%d/%Y')
else you're comparing strings instead.
Note:
It would be better to use a proper DATE or DATETIME column instead.
With the current VARCHAR format MySQL is unable to use indexes. That's very bad for performance.
You can convert your data by adding another column to your table:
ALTER TABLE tasks
ADD COLUMN new_due_date DATE;
Then you use an UPDATE statement to fill this new column
UPDATE tasks
SET new_due_date = STR_TO_DATE(due_date, '%m/%d/%Y');
If you don't need your old column anymore then you can delete this column and modify the new column to have the name of the old one. Then you will have your table with all your data in a DATE column.
I have the following table in MySQL that records event counts of stuff happening each day
event_date event_count
2011-05-03 21
2011-05-04 12
2011-05-05 12
I want to be able to query this efficiently by date range AND by day of week. For example - "What is the event_count on Tuesdays in May?"
Currently the event_date field is a date type. Are there any functions in MySQL that let me query this column by day of week, or should I add another column to the table to store the day of week?
The table will hold hundreds of thousands of rows, so given a choice I'll choose the most efficient solution (as opposed to most simple).
Use DAYOFWEEK in your query, something like:
SELECT * FROM mytable WHERE MONTH(event_date) = 5 AND DAYOFWEEK(event_date) = 7;
This will find all info for Saturdays in May.
To get the fastest reads store a denormalized field that is the day of the week (and whatever else you need). That way you can index columns and avoid full table scans.
Just try the above first to see if it suits your needs and if it doesn't, add some extra columns and store the data on write. Just watch out for update anomalies (make sure you update the day_of_week column if you change event_date).
Note that the denormalized fields will increase the time taken to do writes, increase calculations on write, and take up more space. Make sure you really need the benefit and can measure that it helps you.
Check DAYOFWEEK() function
If you want textual representation of day of week - use DAYNAME() function.