Should I use SMALLINT instead of DATETIME in MySQL to save space? - mysql

I'm trying to decide whether to use SMALLINT(4) vs DATETIME to represent a year in MYSQL.
My table needs to have the model year, but I don't want to waste space with month or date like this: 20xx-01-01 00:00:00.
So I could save space representing a year like this:
year SMALLINT(4);
If it's not a big savings, I'm fine using DATETIME. If using 4 digit year is good for saving space, then how do I $_POST a four-digit year as a DATETIME?

There is year data type in MySQL - http://dev.mysql.com/doc/refman/5.1/en/year.html
The YEAR type is a 1-byte type used to represent year values. It can be declared as YEAR(4) or YEAR(2) to specify a display width of four or two characters. The default is four characters if no width is given.
NOTE:
The YEAR(2) data type has certain issues that you should consider before choosing to use it. As of MySQL 5.1.65, YEAR(2) is deprecated.
Possible range : 1901 to 2155, or 0000

You'd use mktime(date(Y), 0, 0, 0, 0, 0)

You can use DATE data type (uses 3 bytes) instead of DATETIME (8 bytes). You still have to store the month and day, but you don't need to store the time.

MySQL DATE type allocates 3 bytes, while SMALLINT is 2-byte integer. So, it's eager savings, if any. On the other hand, every time you want to compare year-as-integer column with other date column, you need to do an extra work.
To convert integer input value to MySQL date you can use something like this:
$year = isset($_POST['year']) ? intval($_POST['year']) : 1970;
// ISO 8601 standard date representation is YYYY-MM-DD
mysqli_query($link, "INSERT INTO `mytable`(`datefield`) VALUES('{$year}-01-01')");

Related

MySQL string to date brings all rows with the same year

I have a table that the data is a text in the format: 05/07/2019 (dd/mm/yyyy).
When I try to convert it to a date with
str_to_date(date_field,'%d/%m/%y')
I get the response in the format 2020-06-21 (yyyy-mm-dd). But the problem is that in the result all of the years are 2020 though this isn't the actual sitatuion.
Is there a way to solve this or do I need to recreate the DB with the date to be in date format?
If you are using the format dd/mm/yyyy you need to use capital Y
%Y Year as a numeric, 4-digit value
%y Year as a numeric, 2-digit value
So, in your case, you should use str_to_date(date_field,'%d/%m/%Y') because when you use y, it is taking only the first two digits for the year.
And, as I said in my comment (and Tim also said) if you are storing dates in a RDBMS, you should use ALWAYS proper date/datetime data types.

MySQL timestamp format and datediff

Hi I'm writing queries for MySQL, and now my database has a column containing the timestamp in this format: 7/14/2015 7:57:49 AM, but I need to use the DATEDIFF function, so how can I convert the timestamp into the format like: 2015-7-14 (or 2015-07-14, I'm not sure which one is correct; just the date)?
This should convert your string to just the date in a date format, then you can use DATEDIFF on the date fields in question:
SELECT STR_TO_DATE(LEFT(t,LOCATE(' ',t) - 1), '%m/%d/%Y') FROM my_table;
The LEFT function will take the substring to the left of the space, which is just your date, then STR_TO_DATE will convert that substring to a date the system can use.
(Not knowing your field and table names, I used t and my_table.)
You don't need to. The way MySQL displays timestamps has nothing to do with the way they're stored internally; as long as it's TYPE TIMESTAMP or some compatible type, the DATEDIFF() function will know what to do with it.
TIMESTAMPs are actually stored as a really huge integer representing (I think) milliseconds from Midnight UTC, January 1st, 1970. The display format is determined by a system global variable, and has nothing to do with the actual value.
Converting from a string to a DATETIME or TIMESTAMP is actually also fairly straightforward using the STR_TO_DATE() function; in your case the format string would be something like
STR_TO_DATE('%c/%e/%Y %l:%i:%s %p', datecol)
although you might have to experiment a bit to make it work reliably.

MySQL and datetime

If I have a table with a DATETIME column I can insert dates that have a format like:
2015-03-25 10:10:10
2015-03-25 10:10
2015-03-25 10
2015-03-25
It will fill in the remainder with zeros. I can't however use
2015-03
2015
As it will give an 'Incorrect datetime value' error. It is however possible to use these last two in a SELECT like [..] WHERE timestamp < '2015-03' ..
Is there a way that MySQL will fill in the remainder of datetimes with 01-01 for the month and day if omitted in datetimes or do I have to do that manually myself?
I.e. I would like to use '2015-03' in an INSERT statement, or do something like SELECT DATE_FORMAT('2015-03', '%Y%m%dT%H%i%S')
As stated in Date and Time Literals:
MySQL recognizes DATE values in these formats:
As a string in either 'YYYY-MM-DD' or 'YY-MM-DD' format. A “relaxed” syntax is permitted: Any punctuation character may be used as the delimiter between date parts. For example, '2012-12-31', '2012/12/31', '2012^12^31', and '2012#12#31' are equivalent.
As a string with no delimiters in either 'YYYYMMDD' or 'YYMMDD' format, provided that the string makes sense as a date. For example, '20070523' and '070523' are interpreted as '2007-05-23', but '071332' is illegal (it has nonsensical month and day parts) and becomes '0000-00-00'.
As a number in either YYYYMMDD or YYMMDD format, provided that the number makes sense as a date. For example, 19830905 and 830905 are interpreted as '1983-09-05'.
MySQL recognizes DATETIME and TIMESTAMP values in these formats:
As a string in either 'YYYY-MM-DD HH:MM:SS' or 'YY-MM-DD HH:MM:SS' format. A “relaxed” syntax is permitted here, too: Any punctuation character may be used as the delimiter between date parts or time parts. For example, '2012-12-31 11:30:45', '2012^12^31 11+30+45', '2012/12/31 11*30*45', and '2012#12#31 11^30^45' are equivalent.
The only delimiter recognized between a date and time part and a fractional seconds part is the decimal point.
The date and time parts can be separated by T rather than a space. For example, '2012-12-31 11:30:45' '2012-12-31T11:30:45' are equivalent.
As a string with no delimiters in either 'YYYYMMDDHHMMSS' or 'YYMMDDHHMMSS' format, provided that the string makes sense as a date. For example, '20070523091528' and '070523091528' are interpreted as '2007-05-23 09:15:28', but '071122129015' is illegal (it has a nonsensical minute part) and becomes '0000-00-00 00:00:00'.
As a number in either YYYYMMDDHHMMSS or YYMMDDHHMMSS format, provided that the number makes sense as a date. For example, 19830905132800 and 830905132800 are interpreted as '1983-09-05 13:28:00'.
Notably, MySQL does not support the incomplete formats that you wish to use.
That MySQL happens to accept some of the incomplete formats you've tried (apparently by padding with zeroes) is undocumented behaviour, quite possibly unintended by the developers. It cannot (and should not) be relied upon, not least because edge cases could exist under which the behaviour breaks; or because the behaviour could be changed without warning in a future release.
If it's absolutely necessary to provide such incomplete temporal literals to MySQL (which it shouldn't be, as your data access layer ought to be aware of the type of values it is handling and provide them to MySQL in a supported format), you can use its STR_TO_DATE() function to parse them accordingly:
Unspecified date or time parts have a value of 0, so incompletely specified values in str produce a result with some or all parts set to 0:
mysql> SELECT STR_TO_DATE('abc','abc');
-> '0000-00-00'
mysql> SELECT STR_TO_DATE('9','%m');
-> '0000-09-00'
mysql> SELECT STR_TO_DATE('9','%s');
-> '00:00:09'
Range checking on the parts of date values is as described in Section 11.3.1, “The DATE, DATETIME, and TIMESTAMP Types”. This means, for example, that “zero” dates or dates with part values of 0 are permitted unless the SQL mode is set to disallow such values.
So, for example, you might use:
STR_TO_DATE('2015-03', '%Y-%m');
Try unix_timestamp()
SELECT like [..] WHERE unix_timestamp(timestamp) < '2015-03'

phpMyAdmin - Storing time in mm:ss:ms format

In phpMyAdmin I'm wanting to record a lap time for a race. The format needs to be in mm:ss:ms format.
How can I store this value in the database? Is there a data type that will allow it? I've tried time, timestamp and datetime but none of them store the value with milliseconds.
If this is not possible can I store it as an int or a varchar and then convert it in a select query to mm:ss:ms format for output display purposes?
Example Output:
1:35.547
So that's:
1 minute, 35 secs, 547 milliseconds
Any ideas?
MySQL 5.6.4 and up expands fractional seconds support for TIME, DATETIME, and TIMESTAMPvalues, with up to microseconds (6 digits) precision.
http://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html
In earlier versions you have to implement the feature manually. The simplest option I can think of would be storing the milliseconds in a separate SMALLINT column, then:
SELECT CONCAT(
TIME_FORMAT(time_col, '%i minutes, %s seconds, '),
milliseconds_col,
' milliseconds'
) FROM ...
Alternatively, you could store your times as DECIMAL(10, 3). Unfortunately both approaches require cumbersome, manual conversions.

Convert decimal stored as varchar to datetime

I've inherited a MySQL database with a date column type of Varchar.
The column contains decimal strings. For example: 41143.646585648.
How would I go about converting this into DateTime format?
All you need to know is the date the original developer defined as the value zero. Then it's a simple matter of adding the integer number of days to that date, then multiplying the fractional part by 86400 to get seconds and doing the arithmetic to determine the hour, minute and second.
If you have a row where you know the actual date and the stored value you can determine the zero date easily by subtraction.
You could string replace the dot, but the remaining count of numbers is to high for a unix timestamp. I don't know how the date was converted to decimal. Maybe you should split your string rather than string replace.
Maybe this code gives you some ideas for a solution:
#SELECT FROM_UNIXTIME(REPLACE('41143.646585648', '.', '')); # Does not work due to wrong amount of numbers in string
SELECT FROM_UNIXTIME(REPLACE('13577.77916', '.', '')); # works