MySQL Inserting invalid dates - mysql

again, this qn was from the practice qns in the mysql certification guide book ...
QUESTION
Here's the structure of a table typetest with three columns (number, string, and dates). As- sume the server is running in MySQL's “forgiving” SQL mode.
mysql> DESCRIBE typetest;
+--------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+-------+
| number | tinyint(3) unsigned | YES | | NULL | |
+--------+---------------------+------+-----+---------+-------+
You perform the following INSERT operation on table typetest:
INSERT INTO typetest VALUES (1000,'yoodoo','999-12-31');
What data values will actually be stored in the table? Provide a short explanation.
ANSWER
+--------+--------+------------+
| number | string | dates |
+--------+--------+------------+
| 255 | yoodo | 0000-00-00 |
+--------+--------+------------+
The inserted number 1000 is too big to fit in the TINYINT UNSIGNED column, so the highest pos- sible value (255) is inserted. 'yoodoo' is too long for a CHAR(5) column and is thus truncated to five characters. '999-12-31' is a date that is earlier than the earliest possible DATE value ('1000-01-01'). This is interpreted as an invalid date, so the “zero” date is stored.
when i tried inserting '999-12-31' into a date i get 0999-12-31. i read some where in the certification guide that mysql may be able to insert dates out of the range 1000-01-01 to 9999-12-31. but in the exam what do i answer?

You can read the Constraints on Invalid Data section. Unfortunately it doesn't give a straight answer for your question. It says "If the date is totally wrong (outside the server's ability to store it), the special “zero” date value '0000-00-00' is stored in the column instead.", and I would say storing 0999 isn't impossible...

Found this reported as a bug. The official response is that you can do it, but it is not supported, and you are on your own.

Exams and real life are different things. It's difficult to prove your opinion, if in book writed another. But i would answer that i tested by my own.

Mysql Date Range: 1000-01-01 to 9999-12-31 (ref)
Here you are trying to insert '999-12-31'. Since this date is not in the above range mysql defaults the value to 0

Related

How to tackle data truncation error when copying rows from one table to another, both tables having same schema?

Database has two tables with same schema.
date VARCHAR(20),
track VARCHAR(150),
race_number INT,
horse_number INT,
early_last5 FLOAT(10,1),
PRIMARY KEY (track, race_number, horse_number, date)
One is named sectional_table and another is window_sectional_table.
I want to copy all contents of sectional table to window_sectional_table.
I do the most logical thing possible.
INSERT INTO window_sectional_table SELECT * FROM sectional_table;
Unfortunately, I am terrorized by this error.
Data truncated for column 'early_last5' at row 1
I investigate row 1. Row 1 looks like this.
+------------+----------+-------------+--------------+-------------+
| date | track | race_number | horse_number | early_last5 |
+------------+----------+-------------+--------------+-------------+
| 2021-05-03 | GUNNEDAH | 1 | 1 | 0.0 |
+------------+----------+-------------+--------------+-------------+
How do I proceed? I believe the value 0.0 should have been auto filled for null value.
The Data truncated for column 'early_last5' at row 1 error is referring to your INSERT statement rather than which specific value in the database is being truncated.
I believe the value 0.0 should have been auto filled for null value.
Nope. That’s not defined in your INSERT and it’s not defined in the table creation statement.
How do I proceed?
The simplest method would be to convert the FLOAT value to a DECIMAL for the INSERT, complete with an IFNULL if you want NULL to be converted to 0.0. The FLOAT data type has long been a thorn in the side of many people who expect it to work like a typical decimal.
Here’s a quick SQL statement that should get you moving again:
INSERT INTO `window_sectional_table` (`date`, `track`, `race_number`, `horse_number`, `early_last5`)
SELECT `date`, `track`, `race_number`, `horse_number`,
CAST(IFNULL(`early_last5`, 0) AS DECIMAL(10,1))
FROM `sectional_table`
ORDER BY `track`, `race_number`, `horse_number`, `date`;

Why are numbers inserted into a VARCHAR column without the ' ' but string texts aren't?

So I tried to experiment with the INSERT INTO code. I tried using the statement,
INSERT INTO cats (name, age)
VALUES ( 8, '3');
just to try it out and see what happens. It turns out it's still able to store both values. Under name, was 8, and under age was 3. I also tried to insert the name, Momo, without any quotes but it did not work. How come the number 8, worked without the ' ' and Momo didn't'? Also, how come when I use ' ' for the integer, 3, it still took that value as age?
Last part of the question that I just want to clarify. I tried inserting 'Mimi' in the age value and the table showed 0. I just assumed that meant a null value because 'Mimi' isn't an integer. Is that correct? If so, then why did '3' work?
For more clarification, my cats table looks like this
mysql> SHOW COLUMNS FROM cats;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| name | varchar(100) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
I'm a true beginner so I'm sorry for the very simple question
In SQL, string constants need to be surrounded by single quotes. Otherwise, they are interpreted as an identifier -- presumably a column name in most contexts, but it could also be a variable name.
A values() statement has no way to reference columns, so Momo will generate an error that the identifier is not recognized. Note that double quotes are an exception in some databases, including MySQL. They can surround either identifiers or string values.
In a numeric context, such as when inserting a value into a numeric column, SQL converts strings to numbers. In most cases, the SQL will generate an error, if the string does not convert cleanly to a number.
I think the assumption you are making is that '8' is a string, and 8 is an integer.
Making this assumption is usually a good one, in most programming languages. The SQL language however is more lenient. It already knows what the column type is, so it can figure out how to store the value and what you meant.
So in a lot of cases 8 and '8' and "8" are identical.

(mysql query performance issues) Indexing of large historical share price database

this might be a trivial question for some of you but I haven't found/understood a solution to the following problem:
I have a large c 60 GB database structured the following way:
| Field | Type | Null | Key | Default | Extra |
+------------+----------+------+-----+---------+-------+
| date | datetime | YES | MUL | NULL | |
| chgpct1d | double | YES | | NULL | |
| pair | text | YES | | NULL | |
The database stores the last 10 years of daily percentage changes for c 200k different pair-trades. Thus, neither date nor pair is a unique key (a combination of date + pair would be). There are c 2600 distinct date entries and c 200k distinct pairs which generate > 520 MM rows.
The following query takes c multiple minutes to return a result.
SELECT date, chgpct1d, pair FROM db WHERE date = '2018-12-20';
What can I do to speed things up?
I've read about multiple-column indices but I'm not sure if that would help in my case given that all of the WHERE-queries will only ever point to the 'date' field.
MySQL probably does a full table scan to satisfy your query. That's like looking up a word in a dictionary that has its entries in random order: very slow.
Two things:
Create an index on these columns: (date, chgpct1d, pair).
Because the column named date has the DATETIME data type, it can potentially contain values like 2018-12-20 10:17:20. When you say WHERE date = '2018-12-20' it actually means WHERE date = '2018-12-20 00:00:00'. So, use this instead
WHERE date >= '2018-12-20'
AND date < '2018-12-21`
That will capture all the date values at any time on your chosen date.
Why does this help? Because your multicolumn index starts with date, MySQL can do a range scan on it given the WHERE statement you have. And, because the index contains everything needed by your query the database server doesn't have to look anywhere else, but can satisfy the query directly from the index. That index is said to cover the query.
Notice that with half a gigarow in your table, creating the index will take a while. Do it overnight or something.

MySQL out of range value for decimal column

After searching, I found plenty of out of range problems with people not knowing that the first digit, m, in decimal(m,n) is the total amount of digits. However, that is not my problem.
For the column in question I have the following:
Field | Type | Null | Key | Default | Extra
preco | decimal(50,2) unsigned | NO | | 0.00 |
The setting decimal(50,2) is way more than I really want or need. I really only want 10 digits total. Its a price, so anything over 100 million is probably ridiculous, so decimal(10,2) would probably be more appropriate. However, MySQL Is not accepting the following query:
INSERT INTO `produto` (`tipo_id`, `preco`, `qtd`, `opcao1`) VALUES (110, '77888555.43', '10', 'Azul')
I tried the query through CodeIgniter, phpMyAdmin and directly in the MySQL command line client. I also tried it without the quotes on the decimal value but I always get the same error:
"Out of range value for column 'preco' at row 2"
You are sending the value for preco as a string which is accepted by MySQL in the same way as a numerical value.
I have tried it with SQLyog, it is working perfect. I tried to change both ways in SQLyog directly through Table Data tab and using Query. It is just working. it seems there is no problem in Decimal Range, but problem is some where else. See the screenshots attached
Directly through Table Data Tab
Through insert query
Table Structure
Hope it help...

Common MySQL fields and their appropriate data types

I am setting up a very small MySQL database that stores, first name, last name, email and phone number and am struggling to find the 'perfect' datatype for each field. I know there is no such thing as a perfect answer, but there must be some sort of common convention for commonly used fields such as these. For instance, I have determined that an unformatted US phone number is too big to be stored as an unsigned int, it must be at least a bigint.
Because I am sure other people would probably find this useful, I dont want to restrict my question to just the fields I mentioned above.
What datatypes are appropriate for common database fields? Fields like phone number, email and address?
Someone's going to post a much better answer than this, but just wanted to make the point that personally I would never store a phone number in any kind of integer field, mainly because:
You don't need to do any kind of arithmetic with it, and
Sooner or later someone's going to try to (do something like) put brackets around their area code.
In general though, I seem to almost exclusively use:
INT(11) for anything that is either an ID or references another ID
DATETIME for time stamps
VARCHAR(255) for anything guaranteed to be under 255 characters (page titles, names, etc)
TEXT for pretty much everything else.
Of course there are exceptions, but I find that covers most eventualities.
Here are some common datatypes I use (I am not much of a pro though):
| Column | Data type | Note
| ---------------- | ------------- | -------------------------------------
| id | INTEGER | AUTO_INCREMENT, UNSIGNED |
| uuid | CHAR(36) | or CHAR(16) binary |
| title | VARCHAR(255) | |
| full name | VARCHAR(70) | |
| gender | TINYINT | UNSIGNED |
| description | TINYTEXT | often may not be enough, use TEXT
instead
| post body | TEXT | |
| email | VARCHAR(255) | |
| url | VARCHAR(2083) | MySQL version < 5.0.3 - use TEXT |
| salt | CHAR(x) | randomly generated string, usually of
fixed length (x)
| digest (md5) | CHAR(32) | |
| phone number | VARCHAR(20) | |
| US zip code | CHAR(5) | Use CHAR(10) if you store extended
codes
| US/Canada p.code | CHAR(6) | |
| file path | VARCHAR(255) | |
| 5-star rating | DECIMAL(3,2) | UNSIGNED |
| price | DECIMAL(10,2) | UNSIGNED |
| date (creation) | DATE/DATETIME | usually displayed as initial date of
a post |
| date (tracking) | TIMESTAMP | can be used for tracking changes in a
post |
| tags, categories | TINYTEXT | comma separated values * |
| status | TINYINT(1) | 1 – published, 0 – unpublished, … You
can also use ENUM for human-readable
values
| json data | JSON | or LONGTEXT
In my experience, first name/last name fields should be at least 48 characters -- there are names from some countries such as Malaysia or India that are very long in their full form.
Phone numbers and postcodes you should always treat as text, not numbers. The normal reason given is that there are postcodes that begin with 0, and in some countries, phone numbers can also begin with 0. But the real reason is that they aren't numbers -- they're identifiers that happen to be made up of numerical digits (and that's ignoring countries like Canada that have letters in their postcodes). So store them in a text field.
In MySQL you can use VARCHAR fields for this type of information. Whilst it sounds lazy, it means you don't have to be too concerned about the right minimum size.
Since you're going to be dealing with data of a variable length (names, email addresses), then you'd be wanting to use VARCHAR. The amount of space taken up by a VARCHAR field is [field length] + 1 bytes, up to max length 255, so I wouldn't worry too much about trying to find a perfect size. Take a look at what you'd imagine might be the longest length might be, then double it and set that as your VARCHAR limit. That said...:
I generally set email fields to be VARCHAR(100) - i haven't come up with a problem from that yet. Names I set to VARCHAR(50).
As the others have said, phone numbers and zip/postal codes are not actually numeric values, they're strings containing the digits 0-9 (and sometimes more!), and therefore you should treat them as a string. VARCHAR(20) should be well sufficient.
Note that if you were to store phone numbers as integers, many systems will assume that a number starting with 0 is an octal (base 8) number! Therefore, the perfectly valid phone number "0731602412" would get put into your database as the decimal number "124192010"!!
Any Table ID
Use: INT(11).
MySQL indexes will be able to parse through an int list fastest.
Anything Security
Use: BINARY(x), or BLOB(x).
You can store security tokens, etc., as hex directly in BINARY(x) or BLOB(x). To retrieve from binary-type, use SELECT HEX(field)... or SELECT ... WHERE field = UNHEX("ABCD....").
Anything Date
Use: DATETIME, DATE, or TIME.
Always use DATETIME if you need to store both date and time (instead of a pair of fields), as a DATETIME indexing is more amenable to date-comparisons in MySQL.
Anything True-False
Use: BIT(1) (MySQL 8-only.) Otherwise, use BOOLEAN(1).
BOOLEAN is actually just an alias of TINYINT(1), which actually stores 0 to 255 (not exactly a true/false, is it?).
Anything You Want to call `SUM()`, `MAX()`, or similar functions on
Use: INT(11).
VARCHAR or other types of fields won't work with the SUM(), etc., functions.
Anything Over 1,000 Characters
Use: TEXT.
Max limit is 65,535.
Anything Over 65,535 Characters
Use: MEDIUMTEXT.
Max limit is 16,777,215.
Anything Over 16,777,215 Characters
Use: LONGTEXT.
Max limit is 4,294,967,295.
FirstName, LastName
Use : VARCHAR(255).
UTF-8 characters can take up three characters per visible character, and some cultures do not distinguish firstname and lastname. Additionally, cultures may have disagreements about which name is first and which name is last. You should name these fields Person.GivenName and Person.FamilyName.
Email Address
Use : VARCHAR(256).
The definition of an e-mail path is set in RFC821 in 1982. The maximum limit of an e-mail was set by RFC2821 in 2001, and these limits were kept unchanged by RFC5321 in 2008. (See the section: 4.5.3.1. Size Limits and Minimums.) RFC3696, published 2004, mistakenly cites the email address limit as 320 characters, but this was an "info-only" RFC that explicitly "defines no standards" according to its intro, so disregard it.
Phone
Use: VARCHAR(255).
You never know when the phone number will be in the form of "1800...", or "1-800", or "1-(800)", or if it will end with "ext. 42", or "ask for susan".
ZipCode
Use: VARCHAR(10).
You'll get data like 12345 or 12345-6789. Use validation to cleanse this input.
URL
Use: VARCHAR(2000).
Official standards support URL's much longer than this, but few modern browsers support URL's over 2,000 characters. See this SO answer: What is the maximum length of a URL in different browsers?
Price
Use: DECIMAL(11,2).
It goes up to 11.
I am doing about the same thing, and here's what I did.
I used separate tables for name, address, email, and numbers, each with a NameID column that is a foreign key on everything except the Name table, on which it is the primary clustered key. I used MainName and FirstName instead of LastName and FirstName to allow for business entries as well as personal entries, but you may not have a need for that.
The NameID column gets to be a smallint in all the tables because I'm fairly certain I won't make more than 32000 entries. Almost everything else is varchar(n) ranging from 20 to 200, depending on what you wanna store (Birthdays, comments, emails, really long names). That is really dependent on what kind of stuff you're storing.
The Numbers table is where I deviate from that. I set it up to have five columns labeled NameID, Phone#, CountryCode, Extension, and PhoneType. I already discussed NameID. Phone# is varchar(12) with a check constraint looking something like this: CHECK (Phone# like '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'). This ensures that only what I want makes it into the database and the data stays very consistent. The extension and country codes I called nullable smallints, but those could be varchar if you wanted to. PhoneType is varchar(20) and is not nullable.
Hope this helps!