Set PK in Mysql database with autoincrement(string,int) - mysql

I want to have a composite primarykey with (string,int) format where the string is a default value and int is set to autoincrement. Is it possible to achieve this. I need it in the below format
TC_01
TC_02
TC_03
.
.
.
so on

As the auto incremented value is identified just before insertion into the table, you should better depend on a before insert trigger on your table.
To set the concatenated string as in the form TC_002 etc, you need following steps in the trigger body.
Let us say if your str_field is defined as default 'TC', then
FOR EACH ROW BEGIN
SET NEW.str_field = concat( NEW.str_field, '_', NEW.auto_int_field );
END;
Note:
In case you have input a specific value, that is used for
concatenation.
In case if str_field allows null and you have not defined a default
value and you have not input any value for the same for insertion, the
concat( NEW.str_field, ... results a NULL.
You can define composite unique key on str_field and auto_int_field primary key field.
Constraint UK_CMP unique key ( str_field, auto_int_field )
EDIT:
when i use this trigger am getting str_field as TC_0 in all rows. But i should get TC_1,TC_2 etc.
You need an example like this:
mysql> drop table if exists cmp_pk;
Query OK, 0 rows affected (0.22 sec)
mysql> create table cmp_pk(
-> str varchar(10) not null unique default 'TC_',
-> id int not null auto_increment primary key,
-> constraint uk_cmp unique key( str, id )
-> );
Query OK, 0 rows affected (0.65 sec)
mysql>
mysql> drop trigger if exists bi_cmp_pk;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> delimiter //
mysql> create trigger bi_cmp_pk before insert on cmp_pk
-> for each row begin
-> SET #NEW_ID := ( SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES
-> WHERE TABLE_NAME='cmp_pk' AND TABLE_SCHEMA=DATABASE() );
-> SET NEW.str = concat( NEW.str, #NEW_ID );
-> end;
-> //
Query OK, 0 rows affected (0.07 sec)
mysql> delimiter ;
mysql>
mysql> insert into cmp_pk values();
Query OK, 1 row affected (0.06 sec)
mysql> select * from cmp_pk;
+------+----+
| str | id |
+------+----+
| TC_1 | 1 |
+------+----+
1 row in set (0.00 sec)
mysql>
mysql> insert into cmp_pk values();
Query OK, 1 row affected (0.06 sec)
mysql> select * from cmp_pk;
+------+----+
| str | id |
+------+----+
| TC_1 | 1 |
| TC_2 | 2 |
+------+----+

DELIMITER $$
CREATE TRIGGER bi_cmp_pk
BEFORE INSERT ON cmp_pk
FOR EACH ROW BEGIN
SET #NEW_ID := ( SELECT last_insert_id()+1 from cmp_pk limit 1 );
SET NEW.str = concat( NEW.str, #NEW_ID );
end;
$$ DELIMITER ;
this trigger should solve your problem

Actually i dont know what actually you want but may this code will help you
CREATE TABLE tbl_name (
col1 varchar(255) DEFAULT 'TC_',
id INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY (col1,id));

Related

My MySQL function doesn't insert a value

This is my code:
IF EXISTS(SELECT * FROM User WHERE Username = #Username) THEN
RETURN -1;
ELSEIF EXISTS(SELECT * FROM User WHERE Email = #Email)
THEN
RETURN -2;
ELSE
INSERT INTO User(Username, Password, Email)
VALUES ('Nicki',#Password,#Email);
RETURN LAST_INSERT_ID();
END IF
And an image
But the function doesn't insert a value — can you explain why not?
#Username is a 9.4 User-Defined Variables and Username is a table column.
Also, check: C.1 Restrictions on Stored Programs::Name Conflicts within Stored Routines.
Try:
mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 5.7.18 |
+-----------+
1 row in set (0.00 sec)
mysql> DROP FUNCTION IF EXISTS `InsertUser`;
Query OK, 0 rows affected (0.00 sec)
mysql> DROP TABLE IF EXISTS `User`;
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE TABLE IF NOT EXISTS `User`(
-> `Id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
-> `Username` VARCHAR(255) NOT NULL,
-> `Password` VARCHAR(255) NOT NULL,
-> `Email` VARCHAR(255) NOT NULL
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER //
mysql> CREATE FUNCTION `InsertUser`(`_Username` VARCHAR(255),
-> `_Email` VARCHAR(255),
-> `_Password` VARCHAR(255)
-> )
-> RETURNS INT
-> LANGUAGE SQL
-> DETERMINISTIC
-> MODIFIES SQL DATA
-> BEGIN
-> IF EXISTS(SELECT * FROM `User` WHERE `Username` = `_Username`) THEN
-> RETURN -1;
-> ELSEIF EXISTS(SELECT * FROM `User` WHERE `Email` = `_Email`) THEN
-> RETURN -2;
-> ELSE
-> INSERT INTO `User` (`Username`, `Password`, `Email`)
-> VALUES ('Nicki', `_Password`, `_Email`);
-> RETURN LAST_INSERT_ID();
-> END IF;
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> SELECT
-> `Id`,
-> `Username`,
-> `Password`,
-> `Email`
-> FROM
-> `User`;
Empty set (0.00 sec)
mysql> SELECT `InsertUser`(NULL, 'pass', 'email#domain.ext');
+------------------------------------------------+
| `InsertUser`(NULL, 'pass', 'email#domain.ext') |
+------------------------------------------------+
| 1 |
+------------------------------------------------+
1 row in set (0.01 sec)
mysql> SELECT
-> `Id`,
-> `Username`,
-> `Password`,
-> `Email`
-> FROM
-> `User`;
+----+----------+------------------+-------+
| Id | Username | Password | Email |
+----+----------+------------------+-------+
| 1 | Nicki | email#domain.ext | pass |
+----+----------+------------------+-------+
1 row in set (0.00 sec)
mysql> SELECT `InsertUser`(NULL, 'pass', 'email#domain.ext');
+------------------------------------------------+
| `InsertUser`(NULL, 'pass', 'email#domain.ext') |
+------------------------------------------------+
| -2 |
+------------------------------------------------+
1 row in set (0.00 sec)
Example db-fiddle.

MySQL: Procedure calls within a transaction are causing commits

I have a transaction which calls a generated procedure, however if an error occurs after the procedure I notice that the statements during and before the procedure have been committed. Here is the procedure:
DELIMITER $$
CREATE PROCEDURE location_processor(in _city varchar(20), in _country_code varchar(2), out id int)
begin
select location_id into id from location where city = _city and country_code = _country_code limit 0,1;
if id is null then
select #id := max(location_id) from location;
if #id is null then
set #id = 0;
end if;
set #id = #id + 1;
insert into location (location_id, city, country_code)
values(#id, _city, _country_code);
set id = #id;
end if;
end; $$
DELIMITER ;
Note: there is no start/end transaction syntax used within this procedure; although I have reason to believe that begin and end of the procedure itself is causing commit as:
Note:
Within all stored programs (stored procedures and functions, triggers, and events), the parser treats BEGIN [WORK] as the beginning of a BEGIN ... END block. Begin a transaction in this context with START TRANSACTION instead.
(https://dev.mysql.com/doc/refman/5.7/en/commit.html)
I need this procedure for error checking purposes. Is there anyway to avoid committing within a transaction whilst using a procedure within it?
With a simple example, I can't reproduce the problem:
mysql> DROP PROCEDURE IF EXISTS `location_processor`;
Query OK, 0 rows affected (0.00 sec)
mysql> DROP TABLE IF EXISTS `location`;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE IF NOT EXISTS `location` (
-> `location_id` INT,
-> `city` VARCHAR(255),
-> `country_code` VARCHAR(255)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER //
mysql> CREATE PROCEDURE `location_processor`()
-> BEGIN
-> INSERT INTO `location`
-> (`location_id`, `city`, `country_code`)
-> VALUES
-> (2, 'city', 'country_code');
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT `location_id`, `city`, `country_code`
-> FROM `location`;
Empty set (0.00 sec)
mysql> INSERT INTO `location`
-> (`location_id`, `city`, `country_code`)
-> VALUES
-> (1, 'city', 'country_code');
Query OK, 1 row affected (0.00 sec)
mysql> CALL `location_processor`;
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO `location`
-> (`location_id`, `city`, `country_code`)
-> VALUES
-> (3, 'city', 'country_code');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `location_id`, `city`, `country_code`
-> FROM `location`;
+-------------+------+--------------+
| location_id | city | country_code |
+-------------+------+--------------+
| 1 | city | country_code |
| 2 | city | country_code |
| 3 | city | country_code |
+-------------+------+--------------+
3 rows in set (0.00 sec)
mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT `location_id`, `city`, `country_code`
-> FROM `location`;
Empty set (0.00 sec)

trigger in mysql between two database in mysql

I need a trigger between two database when a row insert to tbl1 in db1,this row insert into tbl2 in db2.
CREATE TRIGGER `update_users` AFTER INSERT ON `db1`.`tbl1`
FOR EACH ROW INSERT INTO `db2`.`tbl2` (id,email,password)
VALUES
(???)
what is write in VALUES??
See example:
mysql> CREATE DATABASE `db1`;
Query OK, 1 row affected (0.00 sec)
mysql> CREATE DATABASE `db2`;
Query OK, 1 row affected (0.00 sec)
mysql> USE `db1`;
Database changed
mysql> CREATE TABLE `tbl1` (
-> `id` INT UNSIGNED,
-> `email` VARCHAR(255),
-> `password` VARCHAR(255)
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> DELIMITER //
mysql> CREATE TRIGGER `update_users` AFTER INSERT ON `tbl1`
-> FOR EACH ROW
-> BEGIN
-> INSERT INTO `db2`.`tbl2` (`id`, `email`, `password`)
-> VALUES
-> (NEW.`id`, NEW.`email`, NEW.`password`);
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> USE `db2`;
Database changed
mysql> CREATE TABLE `tbl2` (
-> `id` INT UNSIGNED,
-> `email` VARCHAR(255),
-> `password` VARCHAR(255)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> USE `db1`;
Database changed
mysql> INSERT INTO `tbl1` VALUES (1, 'email#email.net', 'secret');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `id`, `email`, `password` FROM `tbl1`;
+------+-----------------+----------+
| id | email | password |
+------+-----------------+----------+
| 1 | email#email.net | secret |
+------+-----------------+----------+
1 row in set (0.00 sec)
mysql> SELECT `id`, `email`, `password` FROM `db2`.`tbl2`;
+------+-----------------+----------+
| id | email | password |
+------+-----------------+----------+
| 1 | email#email.net | secret |
+------+-----------------+----------+
1 row in set (0.00 sec)

MySQL integer default value 0

I have 4 integer columns in my table. They are not required to be filled. So some of them may be filled, some not.
When they are not filled, MySQL adds 0 to that column. I tried to change the column default value to NULL and it told "Invalid default value".
Is there any way to get an empty row without having there zero?
"Is there any way to get empty row without having there the zero?"
To have NULL in the column by default use the following syntax in create table:
`column` int(10) unsigned DEFAULT NULL,
To alter the existing column:
ALTER TABLE table_name CHANGE COLUMN `column_name` `column_name` int(10) unsigned DEFAULT NULL;
If your columns are NULL'able then it should work just fine
mysql> CREATE TABLE Table1
-> (id int not null auto_increment primary key,
-> `col1` int, `col2` int, `col3` int, `col4` int);
Query OK, 0 rows affected (0.03 sec)
mysql>
mysql> INSERT INTO Table1 (`col1`, `col2`, `col3`, `col4`)
-> VALUES (1, 1, 1, 1);
Query OK, 1 row affected (0.03 sec)
mysql>
mysql> INSERT INTO Table1 () VALUES();
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM table1;
+----+------+------+------+------+
| id | col1 | col2 | col3 | col4 |
+----+------+------+------+------+
| 1 | 1 | 1 | 1 | 1 |
| 2 | NULL | NULL | NULL | NULL |
+----+------+------+------+------+
2 rows in set (0.00 sec)
In that case you need to change your datatype into varchar and add default value NULL.
ALTER TABLE <table_name>
ALTER COLUMN <column_name1> <datatype1> <constraint1>
You have to alter your column to allow NULL values. This question has already been answered before:
How do I modify a MySQL column to allow NULL?

How to check if INSERT went well in stored function?

I'm creating a stored function which should insert new row to table. In this table is also one unique column.
How can I check if everything goes well and row really was inserted?
How can I check exactly that it's this unique column found (for example - try to add duplicate value)?
You can check the LAST_INSERT_ID() function and INSERT IGNORE.
If the INSERT IGNORE was successful, you get the primary key returned. Let's create a table with an auto increment primary key and a unique key on a name.
use test
DROP TABLE IF EXISTS nametable;
CREATE TABLE nametable
(
id int not null auto_increment,
name varchar(20) not null,
primary key (id),
unique key (name)
);
DELIMITER $$
DROP FUNCTION IF EXISTS `test`.`InsertName` $$
CREATE FUNCTION `test`.`InsertName` (newname VARCHAR(20)) RETURNS INT
BEGIN
INSERT IGNORE INTO test.nametable (name) VALUES (newname);
RETURN LAST_INSERT_ID();
END $$
DELIMITER ;
SELECT InsertName('rolando');
SELECT InsertName('rolando');
SELECT InsertName('pamela');
SELECT InsertName('pamela');
SHOW CREATE TABLE test.nametable\G
SELECT * FROM test.nametable;
Here is the example being run:
mysql> use test
Database changed
mysql> DROP TABLE IF EXISTS nametable;
Query OK, 0 rows affected (0.04 sec)
mysql> CREATE TABLE nametable
-> (
-> id int not null auto_increment,
-> name varchar(20) not null,
-> primary key (id),
-> unique key (name)
-> );
Query OK, 0 rows affected (0.07 sec)
mysql> DELIMITER $$
mysql> DROP FUNCTION IF EXISTS `test`.`InsertName` $$
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE FUNCTION `test`.`InsertName` (newname VARCHAR(20)) RETURNS INT
-> BEGIN
-> INSERT IGNORE INTO test.nametable (name) VALUES (newname);
-> RETURN LAST_INSERT_ID();
-> END $$
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> SELECT InsertName('rolando');
+-----------------------+
| InsertName('rolando') |
+-----------------------+
| 1 |
+-----------------------+
1 row in set (0.03 sec)
mysql> SELECT InsertName('rolando');
+-----------------------+
| InsertName('rolando') |
+-----------------------+
| 0 |
+-----------------------+
1 row in set (0.02 sec)
mysql> SELECT InsertName('pamela');
+----------------------+
| InsertName('pamela') |
+----------------------+
| 3 |
+----------------------+
1 row in set (0.02 sec)
mysql> SELECT InsertName('pamela');
+----------------------+
| InsertName('pamela') |
+----------------------+
| 0 |
+----------------------+
1 row in set (0.03 sec)
mysql> SHOW CREATE TABLE test.nametable\G
*************************** 1. row ***************************
Table: nametable
Create Table: CREATE TABLE `nametable` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql> SELECT * FROM test.nametable;
+----+---------+
| id | name |
+----+---------+
| 3 | pamela |
| 1 | rolando |
+----+---------+
2 rows in set (0.00 sec)
mysql>
As shown in the preceding example, you can check the return value of the function. A nonzero return value means the INSERT IGNORE went well. A zero return value indicates a duplicate key without introducing an error number to the mysqld.
The drawback to this approach is that you cannot go back and use id 2 and 4 because of failed attempts to INSERT IGNORE in the event of a duplicate key.
Let's try another example with a different stored function setup using INSERT and without using LAST_INSERT_ID():
use test
DROP TABLE IF EXISTS nametable;
CREATE TABLE nametable
(
id int not null auto_increment,
name varchar(20) not null,
primary key (id),
unique key (name)
);
DELIMITER $$
DROP FUNCTION IF EXISTS `test`.`InsertName` $$
CREATE FUNCTION `test`.`InsertName` (newname VARCHAR(20)) RETURNS INT
BEGIN
DECLARE rv INT;
SELECT COUNT(1) INTO rv FROM test.nametable WHERE name = newname;
IF rv = 0 THEN
INSERT INTO test.nametable (name) VALUES (newname);
END IF;
RETURN rv;
END $$
DELIMITER ;
SELECT InsertName('rolando');
SELECT InsertName('rolando');
SELECT InsertName('pamela');
SELECT InsertName('pamela');
SHOW CREATE TABLE test.nametable\G
SELECT * FROM test.nametable;
Here is the result:
mysql> use test
Database changed
mysql> DROP TABLE IF EXISTS nametable;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> CREATE TABLE nametable
-> (
-> id int not null auto_increment,
-> name varchar(20) not null,
-> primary key (id),
-> unique key (name)
-> );
Query OK, 0 rows affected (0.10 sec)
mysql> DELIMITER $$
mysql> DROP FUNCTION IF EXISTS `test`.`InsertName` $$
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE FUNCTION `test`.`InsertName` (newname VARCHAR(20)) RETURNS INT
-> BEGIN
-> DECLARE rv INT;
-> SELECT COUNT(1) INTO rv FROM test.nametable WHERE name = newname;
-> IF rv = 0 THEN
-> INSERT INTO test.nametable (name) VALUES (newname);
-> END IF;
-> RETURN rv;
-> END $$
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> SELECT InsertName('rolando');
+-----------------------+
| InsertName('rolando') |
+-----------------------+
| 0 |
+-----------------------+
1 row in set (0.04 sec)
mysql> SELECT InsertName('rolando');
+-----------------------+
| InsertName('rolando') |
+-----------------------+
| 1 |
+-----------------------+
1 row in set (0.00 sec)
mysql> SELECT InsertName('pamela');
+----------------------+
| InsertName('pamela') |
+----------------------+
| 0 |
+----------------------+
1 row in set (0.03 sec)
mysql> SELECT InsertName('pamela');
+----------------------+
| InsertName('pamela') |
+----------------------+
| 1 |
+----------------------+
1 row in set (0.00 sec)
mysql> SHOW CREATE TABLE test.nametable\G
*************************** 1. row ***************************
Table: nametable
Create Table: CREATE TABLE `nametable` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql> SELECT * FROM test.nametable;
+----+---------+
| id | name |
+----+---------+
| 2 | pamela |
| 1 | rolando |
+----+---------+
2 rows in set (0.00 sec)
mysql>
In this example, the stored function returns 0 if the INSERT was OK, and returns 1 with a duplicate key on the name. The advantage? No wasted id numbers for auto_increment. The disadvantage? Doing a SELECT statement each time to check for the name already being present in the table.
You have a choice as to which way you want to handle duplicate keys. The first method lets mysqld handle the condition of the INSERT IGNORE. The second method has the stored function checking for the duplicate key first before the INSERT.
Stored Procedures are "all-or-nothing"
Therefore, if you include an INSERT in the sproc, and that INSERT fails on a duplicate key error, the entire sproc will be rolled back.
If the sproc executes without error, you can be confident that the INSERT did not have an error. Now, this does not mean the INSERT actually happens just because the sproc completes, just that there were no errors.... for example, if you had some WHERE clause which excludes the INSERT but doesn't throw an error then there may be some ambiguity.