How can we add a constraint which enforces a column to have only positive values.
Tried the following mysql statement but it doesn't work
create table test ( test_column integer CONSTRAINT blah > 0);
You would use the keyword unsigned to signify that the integer doesn't allow a "sign" (i.e. - it can only be positive):
CREATE TABLE test (
test_column int(11) unsigned
);
You can read more about the numeric data types (signed & unsigned) here.
As far as an actual constraint to prevent the insertion-of negative values, MySQL has a CHECK clause that can be used in the CREATE TABLE statement, however, according to the documentation:
The CHECK clause is parsed but ignored by all storage engines.
For reference, here is how you would use it (and though it will execute absolutely fine, it just does nothing - as the manual states):
CREATE TABLE test (
test_column int(11) unsigned CHECK (test_column > 0)
);
UPDATE (rejecting negative values completely)
I've noticed from a few of your comments that you want queries with negative values to be completely rejected and not set to 0 (as a normal transaction into an unsigned column would do). There is no constraint that can do this in-general (that I know of, at least), however, if you turn strict-mode on (with STRICT_TRANS_TABLES) any query that inserts a negative value into an unsigned column will fail with an error (along with any-other data-insertion errors, such as an invalid enum value).
You can test it by running the following command prior to your insert-commands:
SET ##SESSION.sql_mode = 'STRICT_TRANS_TABLES';
And if it works for you, you can either update your MySQL config with sql-mode="STRICT_TRANS_TABLES" or use SET ##GLOBAL.sql_mode = 'STRICT_TRANS_TABLES'; (I'm not sure if the SET command will affect the global mysql config though, so it may be better to update the actual config-file).
As of MySQL 8.0.16 (MariaDB 10.2.1), CHECK constraints are enforced. (In earlier versions constraint expressions were accepted in the syntax but ignored).
Therefore you can use:
CREATE TABLE test (
test_column INT CHECK (test_column > 0)
);
or
CREATE TABLE test (
test_column INT,
CONSTRAINT test_column_positive CHECK (test_column > 0)
);
The way to fix this is to explicitly tell MySQL Server to create an Unsigned integer.
CREATE TABLE tbl_example (
example_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
example_num INT UNSIGNED NOT NULL,
example_text TEXT
PRIMARY KEY (`example_id`)
);
just use unsigned to allow only positive values.
CREATE TABLE hello
(
world int unsigned
);
SQLFiddle demo
uncomment the line and you will see the error saying: Data truncation: Out of range value for column 'world' at row 1:
You should use UNSIGNED INTEGER data type. For more information, click here
Related
Im revisiting my database and noticed I had some primary keys that were of type INT.
This wasn't unique enough so I thought I would have a guid.
I come from a microsoft sql background and in the ssms you can
choose type to "uniqeidentifier" and auto increment it.
In mysql however Ive found that you have to make triggers that execute on insert for the tables you want
to generate a guide id for. Example:
Table:
CREATE TABLE `tbl_test` (
`GUID` char(40) NOT NULL,
`Name` varchar(50) NOT NULL,
PRIMARY KEY (`GUID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Trigger:
CREATE TRIGGER `t_GUID` BEFORE INSERT ON `tbl_test`
FOR EACH ROW begin
SET new.GUID = uuid();
Alternatively you have to insert the guid yourself in the backend.
Im no DB expert but still remember that triggers cause performance problems.
The above is something I found here and is 9 years old so I was hoping something has changed?
As far as stated in the documentation, you can use uid() as a column default starting version 8.0.13, so something like this should work:
create table tbl_test (
guid binary(16) default (uuid_to_bin(uuid())) not null primary key,
name varchar(50) not null
);
This is pretty much copied from the documentation. I don't have a recent enough version of MySQL at hand to test this.
You can make a
INSERT INTO `tbl_test` VALUES (uuid(),'testname');
This would generate a new uuid, when you call it.
Or you can also use the modern uuid v4 by using one of these functions instead of the standard uuid(), which is more random than the uuid in mysql
How to generate a UUIDv4 in MySQL?
You can use since 8.0.13
CREATE TABLE t1 (
uuid_field VARCHAR(40) DEFAULT (uuid())
);
But you wanted more than unique, but here are only allowed internal functions and not user defined as for uuid v4, for that uyou need the trogger
As per the documentation, BINARY(x) adds some hidden padding bytes to the end of each entry, & VARCHAR(40) also wastes space by not being encoded directly in binary. Using VARBINARY(16) would be more efficient.
Also, more entropy (unguessability / security) per byte is available from RANDOM_BYTES(16) than standardized UUIDs, because they use some sections to encode constant metadata.
Perhaps the below will work for your needs.
-- example
CREATE TABLE `tbl_test` (
`GUID` VARBINARY(16) DEFAULT (RANDOM_BYTES(16)) NOT NULL PRIMARY KEY,
`Name` VARCHAR(50) NOT NULL
);
Im revisiting my database and noticed I had some primary keys that were of type INT.
This wasn't unique enough so I thought I would have a guid.
I come from a microsoft sql background and in the ssms you can
choose type to "uniqeidentifier" and auto increment it.
In mysql however Ive found that you have to make triggers that execute on insert for the tables you want
to generate a guide id for. Example:
Table:
CREATE TABLE `tbl_test` (
`GUID` char(40) NOT NULL,
`Name` varchar(50) NOT NULL,
PRIMARY KEY (`GUID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Trigger:
CREATE TRIGGER `t_GUID` BEFORE INSERT ON `tbl_test`
FOR EACH ROW begin
SET new.GUID = uuid();
Alternatively you have to insert the guid yourself in the backend.
Im no DB expert but still remember that triggers cause performance problems.
The above is something I found here and is 9 years old so I was hoping something has changed?
As far as stated in the documentation, you can use uid() as a column default starting version 8.0.13, so something like this should work:
create table tbl_test (
guid binary(16) default (uuid_to_bin(uuid())) not null primary key,
name varchar(50) not null
);
This is pretty much copied from the documentation. I don't have a recent enough version of MySQL at hand to test this.
You can make a
INSERT INTO `tbl_test` VALUES (uuid(),'testname');
This would generate a new uuid, when you call it.
Or you can also use the modern uuid v4 by using one of these functions instead of the standard uuid(), which is more random than the uuid in mysql
How to generate a UUIDv4 in MySQL?
You can use since 8.0.13
CREATE TABLE t1 (
uuid_field VARCHAR(40) DEFAULT (uuid())
);
But you wanted more than unique, but here are only allowed internal functions and not user defined as for uuid v4, for that uyou need the trogger
As per the documentation, BINARY(x) adds some hidden padding bytes to the end of each entry, & VARCHAR(40) also wastes space by not being encoded directly in binary. Using VARBINARY(16) would be more efficient.
Also, more entropy (unguessability / security) per byte is available from RANDOM_BYTES(16) than standardized UUIDs, because they use some sections to encode constant metadata.
Perhaps the below will work for your needs.
-- example
CREATE TABLE `tbl_test` (
`GUID` VARBINARY(16) DEFAULT (RANDOM_BYTES(16)) NOT NULL PRIMARY KEY,
`Name` VARCHAR(50) NOT NULL
);
I am trying to concatenate two integers as the default value in a third field. My create table in SQL Server works fine:
CREATE TABLE MEI_Tbl
(
MEI_ID int PRIMARY KEY IDENTITY (1,1),
SRC tinyint NOT NULL DEFAULT '2',
HEI_ID AS (Cast (SRC as varchar)+ Cast (MEI_ID as varchar))
);
but when I try to create it in MySQL, I cannot find the equivalent for the concatenation of the two integers (Line 5 HEI_ID...).
**
I am aware of changing IDENTITY (1,1) to AUTO_INCREMENT for MySQL.
**
I have also tried several concat methods, but to no avail.
MySQL seems happier if I define the datatype for HEI_ID, and I have done so as varchar and int but again no success.
I have spent too much time reading about tool kits to convert SQL Server to MySQL. I just want to create the table in MySQL.
Any input would be appreciated.
MySQL does not support computed columns. Instead, you can use a view:
CREATE TABLE MEI_Tbl (
MEI_ID int PRIMARY KEY AUTO_INCREMENT,
SRC tinyint NOT NULL DEFAULT 2
);
CREATE VIEW v_MEI_Tbl as
SELECT MEI_ID, SRC,
CONCAT(src, mei_d) as HEI_ID
FROM MEI_Tbl
);
Then query from the view.
I try to create a table with an INTEGER attribute which should be limited to positive numbers. I know there is an UNSIGNED option, but that does the wrong thing. As it allows adding -10 as a value. It will just make a 10 out of it.
Is it possible to deny a wrong entry? I tried using CHECK
DROP TABLE Produkt;
CREATE TABLE Produkt (
Bezeichnung VARCHAR(237) PRIMARY KEY,
ProduktNr INTEGER NOT NULL,
Produktart VARCHAR(3) DEFAULT "XXX",
CONSTRAINT onlyPositive CHECK(ProduktNr >= 0)
);
But I can still add -10 as a value... What am I doing wrong?
1) In a strict sql_mode if you define your column as
ProduktNr INT UNSIGNED NOT NULL,
and then try to insert a negative value you'll get an error
ERROR 1264 (22003): Out of range value for column 'ProduktNr' at row 1
Here is SQLFiddle demo. Uncomment insert statement and click Build Schema
2) MySQL still lacks support for CHECK constraints. The CHECK clause is parsed but ignored by all storage engines.
3) On a side note: don't use a VARCHAR(237) column as a PRIMARY KEY, especially if you're using InnoDB engine (all secondary indices on the table also include PK values).
I believe you can just add the check without naming the constraint. This seemed to work for me:
CREATE TABLE Produkt (
Bezeichnung VARCHAR(237),
ProduktNr INTEGER NOT NULL,
Produktart VARCHAR(3) DEFAULT "XXX",
PRIMARY KEY (Bezeichnung),
CHECK(ProduktNr >= 0)
);
I also moved the declaration of the primary key. I'm not 100% certain that you can declare a key the same time as a field, but I did put what I knew.
In my MySQL table I've created an ID column which I'm hoping to auto-increment in order for it to be the primary key.
I've created my table:
CREATE TABLE `test` (
`id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 50 ) NOT NULL ,
`date_modified` DATETIME NOT NULL ,
UNIQUE (
`name`
)
) TYPE = INNODB;
then Inserted my records:
INSERT INTO `test` ( `id` , `name` , `date_modified` )
VALUES (
NULL , 'TIM', '2011-11-16 12:36:30'
), (
NULL , 'FRED', '2011-11-16 12:36:30'
);
I'm expecting that my ID's for the above are 1 and 2 (respectively). And so far this is true.
However when I do something like this:
insert into test (name) values ('FRED')
on duplicate key update date_modified=now();
then insert a new record, I'm expecting it to be 3, however now I'm shown an ID of 4; skipping the place spot for 3.
Normally this wouldn't be an issue but I'm using millions of records which have thousands of updates every day.. and I don't really want to even have to think about running out of ID's simply because I'm skipping a ton of numbers..
Anyclue to why this is happening?
MySQL version: 5.1.44
Thank you
My guess is that the INSERT itself kicks off the code that generates the next ID number. When the duplicate key is detected, and ON DUPLICATE KEY UPDATE is executed, the ID number is abandoned. (No SQL dbms guarantees that automatic sequences will be without gaps, AFAIK.)
MySQL docs say
In general, you should try to avoid using an ON DUPLICATE KEY UPDATE
clause on tables with multiple unique indexes.
That page also says
If a table contains an AUTO_INCREMENT column and INSERT ... ON
DUPLICATE KEY UPDATE inserts or updates a row, the LAST_INSERT_ID()
function returns the AUTO_INCREMENT value.
which stops far short of describing the internal behavior I guessed at above.
Can't test here; will try later.
Is it possible to change your key to unsigned bigint - 18,446,744,073,709,551,615 is a lot of records - thus delaying the running out of ID's
Found this in mysql manual http://dev.mysql.com/doc/refman/5.1/en/example-auto-increment.html
Use a large enough integer data type for the AUTO_INCREMENT column to hold the
maximum sequence value you will need. When the column reaches the upper limit of
the data type, the next attempt to generate a sequence number fails. For example,
if you use TINYINT, the maximum permissible sequence number is 127.
For TINYINT UNSIGNED, the maximum is 255.
More reading here http://dev.mysql.com/doc/refman/5.6/en/information-functions.html#function_last-insert-id it could be inferred that the insert to a transactional table is a rollback so the manual says "LAST_INSERT_ID() is not restored to that before the transaction"
What about for a possible solution to use a table to generate the ID's and then insert into your main table as the PK using LAST_INSERT_ID();
From the manual:
Create a table to hold the sequence counter and initialize it:
mysql> CREATE TABLE sequence (id INT NOT NULL);
mysql> INSERT INTO sequence VALUES (0);
Use the table to generate sequence numbers like this:
mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1);
mysql> SELECT LAST_INSERT_ID();
The UPDATE statement increments the sequence counter and causes the next call to
LAST_INSERT_ID() to return the updated value. The SELECT statement retrieves that
value. The mysql_insert_id() C API function can also be used to get the value.
See Section 20.9.3.37, “mysql_insert_id()”.
It's really a bug how you can see here: http://bugs.mysql.com/bug.php?id=26316
But, apparently, they fixed it on 5.1.47 and it was declared as INNODB plugin problem.
A duplicate, but same problem, you can see here too: http://bugs.mysql.com/bug.php?id=53791 referenced to the first page mentioned here in this answer.