I recently encountered a problem caused by a typo in the database creation script, whereby a column in the database was created as varchar(0) instead of varchar(20).
I expected that I would have gotten an error for 0-length string field, but I didn't. What is the purpose of varchar(0) or char(0) as I wouldn't be able to store any data in this column anyway.
It's not allowed per the SQL-92 standard, but permitted in MySQL. From the MySQL manual:
MySQL permits you to create a column of type CHAR(0). This is useful primarily when you have to be compliant with old applications that depend on the existence of a column but that do not actually use its value. CHAR(0) is also quite nice when you need a column that can take only two values: A column that is defined as CHAR(0) NULL occupies only one bit and can take only the values NULL and '' (the empty string).
Just checked MySQL, it's true that it allows zero-length CHAR and VARCHAR.
Not that it can be extremely useful but I can think of a situation when you truncate a column to 0 length when you no longer need it but you don't want to break existing code that writes something there. Anything you assign to a 0-length column will be truncated and a warning issued, but warnings are not errors, they don't break anything.
As they're similar types, char and varchar, I'm going to venture to guess that the use-case of varchar(0) is the same as char(0).
From the documentation of String Types:
MySQL permits you to create a column of type CHAR(0). This is useful
primarily when you have to be compliant with old applications that
depend on the existence of a column but that do not actually use its
value. CHAR(0) is also quite nice when you need a column that can take
only two values: A column that is defined as CHAR(0) NULL occupies
only one bit and can take only the values NULL and '' (the empty
string).
It's useful in combination with a unique index for if you want to mark one specific row in your table (for instance, because it serves as a default). The unique index ensures that all other rows have to be null, so you can always retrieve the row by that column.
You can use it to store boolean values.
Look this code:
mysql> create table chartest(a char(0));
Query OK, 0 rows affected (0.26 sec)
mysql> insert into chartest value(NULL);
Query OK, 1 row affected (0.01 sec)
mysql> insert into chartest value('');
Query OK, 1 row affected (0.00 sec)
mysql> select 'true' from chartest where a is null;
+------+
| true |
+------+
| true |
+------+
1 row in set (0.00 sec)
mysql> select 'false' from chartest where a is not null;
+-------+
| false |
+-------+
| false |
+-------+
1 row in set (0.00 sec)
We can use NULL to represent true and '' (empty string) to represent false!
According to MySQL reference manual, only NULL occupies one bit.
Related
This is more of an academic question. In a MySQL database, I know tinyint(M) and its differences from tinyint(1) have already been discussed on this site, but I'm wondering something else.
Could a column "REVIEWED TINYINT(5) be used to store the values of 5 different boolean checkboxes in the frontend form? I'm thinking along the lines of treating it as an array. If so, how would they be referenced? Would something like REVIEWED(3) or REVIEWED[3] work for referencing their elements? Would there be a syntax for checking whether all their elements were 1 or 0 (or null)?
TINYINT(1) and TINYINT(5) and TINYINT(12) or any other length are actually stored exactly the same. They are all an 8-bit signed integer. They support integer values from -128 to 127. Or values from 0 to 255 if the column is defined as an unsigned integer.
What's with the "length" argument then? Nothing. It doesn't affect the size of the integer or the number of bits or the range of values. The argument is a display hint only. It's useless unless you use the ZEROFILL option.
mysql> create table mytable (i1 tinyint(1) zerofill, i2 tinyint(5) zerofill, i3 tinyint(12) zerofill);
Query OK, 0 rows affected (0.04 sec)
mysql> insert into mytable values (255,255,255);
Query OK, 1 row affected (0.02 sec)
mysql> select * from mytable;
+------+-------+--------------+
| i1 | i2 | i3 |
+------+-------+--------------+
| 255 | 00255 | 000000000255 |
+------+-------+--------------+
The ZEROFILL option forces the column to be unsigned, and when you query the column, it pads the result with zeroes up to the length you defined for the column. The zeroes are not stored in the database, they are added only when you fetch query results.
The "length" argument of integers is misleading, and it causes a lot of confusion for MySQL users. In hindsight, it would have been better to make the syntax like TINYINT ZEROFILL(12) but it's too late to change it now.
I wanted to enter data in MySql table's primary key field with respect to case sensitivity.
But default it is not considering case sensitivity for table data.
Here is my query.
mysql> select id from product where id = 'a1';
+----+
| id |
+----+
| A1 |
+----+
1 row in set (0.00 sec)
mysql> insert into product values('a1', 'SomeName', 'SomeName', 200, 10, 10);
ERROR 1062 (23000): Duplicate entry 'a1' for key 'product.PRIMARY'
Also i have tried Collation while creating table but not getting result as required.
can any one suggest which collation has to use or any other technique to make table's column domain case sensitive.
ALTER TABLE product
MODIFY COLUMN id VARCHAR(...) COLLATION ..._bin NOT NOT NULL;
Where the ... are the current column size and character set.
The only case-sensitive things I can think of are
base-64
Unix file names
But those do not seem likely as PKs. What is your use case? Most things are better off being case-insensitive.
(A Comment links to a SQL Server suggestion using ALTER DATABASE; that will not work for MySQL since that only changes the default for subsequently created tables.)
Earlier today, I asked for an easy way to store a version number for the SQL table layout you are using in SQLite, and got the suggestion to use PRAGMA user_version. As there is no such thing as a Pragma in MySQL, I was wondering on how you would go about this in MySQL (Except for creating a table named "META" with a column "DB-Scheme-Version").
Just to repeat what I said in the linked question: I'm not looking for a way to find out which version of MySQL is installed, but to save a version nuber that tells me what version of my MySQL-Scheme I am using, without checking every table via script.
I also saw this question, but it only allows me to version single tables. Is there something similar or, preferably, easier, for whole Databases (Since it would be no fun to query every single table seperately)? Thanks in advance.
MySQL's SET GLOBAL would probably work, but I prefer a solution that does not reset itself every time the server reboots and does not require SUPER Privilege and / or access to the configuration file to use. To put it short: It should work with a standard MySQL-Database that you get when you rent a small webhosting package, not the ones you get if you rent a full server, as you tend to have more access to those.
There are a couple of choices, depending on the privileges that you have. The higher privileges you have, the more “elegant” the solution.
The most direct route is to create a stored function, which requires the CREATE ROUTINE privilege. e.g.
mysql> CREATE FUNCTION `mydb`.DB_VERSION() RETURNS VARCHAR(15)
RETURN '1.2.7.2861';
Query OK, 0 rows affected (0.03 sec)
mysql> SELECT `mydb`.DB_VERSION();
+--------------+
| DB_VERSION() |
+--------------+
| 1.2.7.2861 |
+--------------+
1 row in set (0.06 sec)
If your privileges limit you to only creating tables, you can create a simple table and put the version in a default value:
mysql> CREATE TABLE `mydb`.`db_version` (
`version` varchar(15) not null default '1.2.7.2861');
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW COLUMNS FROM `mydb`.`db_version`;
+---------+-------------+------+-----+------------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+------------+-------+
| version | varchar(15) | NO | | 1.2.7.2861 | |
+---------+-------------+------+-----+------------+-------+
1 row in set (0.00 sec)
MySQL questions are some of my favorites on StackOverflow.
Unfortunately, things like this:
SELECT foo, bar, baz, quux, frozzle, lambchops FROM something JOIN somethingelse ON 1=1 JOIN (SELECT * FROM areyouserious) v ON 0=5 WHERE lambchops = 'good';
make my eyes bleed.
Also, attempts at describing your schema often go like this:
I have a table CrazyTable with a column that is a date and it has a primary key of Foo_Key but I want to join on SOMETABLE using a substring of column_bar (which is in CrazyTable) which pertains to the phase of the moon (which I store in moon_phases as a thrice-serialized PHP array).
Here is an example of a question I asked, that had I not followed the steps below, I would never have gotten a satisfactory answer from anyone: I have no shame..
I will answer below with what helps me the most with getting the best answer to your question. What helps you?
Use SHOW CREATE TABLE
This tells me more about your tables than your words ever could:
mysql> show create table magic\G
*************************** 1. row ***************************
Table: magic
Create Table: CREATE TABLE `magic` (
`id` int(11) DEFAULT NULL,
`what` varchar(255) DEFAULT NULL,
`the` datetime DEFAULT NULL,
`heck` text,
`soup_is_good` double DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
CAVEAT: If you have 70 columns in your table, omit the unnecessary ones. What's necessary?
Fields JOINed on
Fields SELECTed
Fields WHEREed on
Use EXPLAIN
This allows me to see how best to optimize your currently working, yet presumably slow query:
mysql> explain select * from magic\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: magic
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
Extra:
1 row in set (0.00 sec)
Use \G
Having to scroll right is generally an inconvenience.
Usual:
mysql> select * from magic;
+------------+-------------------------------+---------------------+-------------------+--------------+
| id | what | the | heck | soup_is_good |
+------------+-------------------------------+---------------------+-------------------+--------------+
| 1000000000 | A really long text string yay | 2009-07-29 22:28:17 | OOOH A TEXT FIELD | 100.5 |
+------------+-------------------------------+---------------------+-------------------+--------------+
1 row in set (0.00 sec)
Better:
mysql> select * from magic\G
*************************** 1. row ***************************
id: 1000000000
what: A really long text string yay
the: 2009-07-29 22:28:17
heck: OOOH A TEXT FIELD
soup_is_good: 100.5
1 row in set (0.00 sec)
CAVEAT: \G obviously turns one row of data into several. This becomes equally cumbersome for several rows of data. Do what looks best.
Use an external pastebin for obnoxiously large chunks of data:
Pastie
gist.github
Let us know your expectations
Slow? - We don't know what slow is to you. Seconds, minutes, hours? It helps to know.
Faster - We don't know this either. What's your expectation of fast?
Frequency - Is this a query that you plan to run just once? Daily? Hundreds or thousands of times a day? This helps us know when it's Good Enough.
Procedure Analyse
select * from yourtable procedure analyse()\G
The above will let others know the max and min values stored in the table. That helps.
Knowing which indexes you have on the tables concerned is vital, imo. You state you are using a substring of column_bar in the where clause - you may need to denormalize and store this substring in another column and then index it. There again cardinality of the column can make it worthless using an index on that column, if (for example) there are only 2 distinct values present. For a useful video tutorial on Performance Tuning Best Practices watch this youtube video by Jay Pipes.
Of course if I put enough rows eventually there will be a repeat. But let's assume I choose a big enough id field.
I want to know if I can assume that the id uniquely identifies the row over time. And if the client sends me an id I want to be able to determine what row it refers or if the row was deleted (or if it is a fake id, but in that case I will not care telling, wrongly, that the row was deleted).
Please refer also to the following: if I restart the database, or backup and restore - will it be continue creating ids where it left - or may be it will decide to "fill in the holes"
If you have a "int not null auto increment primary key" that you never reset, then yes IDs will not be reused.
However, this raises an interesting question - what happens if you happen to reuse an old ID (even though it won't happen by default in MySQL, but the human factor always counts) ?
If your database is properly normalized, cascaded and constrained your application should be able to handle the reuse of an ID.
Edit (since you edited your post, I'll flesh out my answer), about this quote: "And if the client sends me an id I want to be able to determine what row it refers or if the row was deleted". It's always possible to determine what row an ID belongs to if it's not deleted (kind of vital to be able to extract information out of your database).
However if the row the id refers to is deleted, then it's not possible to determine what row it belongs to... since it's not there. If you need this I would advice you to implement some type of auditing functionality, preferably by triggers .
The current autoincrement value is preserved across backup/restores via an extra attribute attached to the table. You can see it in a dump just after the ENGINE=:
mysql> create table foo ( bar int(11) primary key auto_increment );
Query OK, 0 rows affected (0.06 sec)
mysql> insert into foo () values (), (), (), ();
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> show create table foo \G
*************************** 1. row ***************************
Table: foo
Create Table: CREATE TABLE `foo` (
`bar` int(11) NOT NULL auto_increment,
PRIMARY KEY (`bar`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
You can reset it using "ALTER TABLE tablename AUTO_INCREMENT=", but it looks to me like
the attribute value is ignored if it isn't more than the maximum existing id when you do an insert.
also note that the described behaviour of not reusing a previously used ID is valid for the MyISAM engine, but actually is not valid for all available engines.