How to receive results from mysql table where field value is NOT 0 or NULL? If I write condition field!=1, it gives nothing, but there are a lot of fields where field!=1. Why?
UPDATE:
CREATE TABLE `test` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`somevar` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `test` (`id`, `somevar`)
VALUES
(1,1),
(2,0),
(3,NULL),
(4,NULL),
(5,0);
This query
SELECT * FROM `test` WHERE `somevar`!=1
gives back only where somevar=0, but not NUL. how to echo all results where somevar!=1?
You can use NULL-safe equal to operator:
mysql> DROP TABLE IF EXISTS `test`;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE IF NOT EXISTS `test` (
-> `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
-> `somevar` int(11) DEFAULT NULL,
-> PRIMARY KEY (`id`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO `test`
-> (`somevar`)
-> VALUES
-> (1), (0),
-> (NULL), (NULL),
-> (0);
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> SELECT `id`, `somevar`
-> FROM `test`
-> WHERE NOT `somevar` <=> 1;
+----+---------+
| id | somevar |
+----+---------+
| 2 | 0 |
| 3 | NULL |
| 4 | NULL |
| 5 | 0 |
+----+---------+
4 rows in set (0.00 sec)
See db-fiddle.
This has been answered many times on this site. NULL Is neither equal nor not equal to anything else. It cannot be compared in traditional ways. You have to ask for NULL values explicitly.
SELECT * FROM `test` WHERE `somevar`!=1 OR `somevar` IS NULL
You can use somevar IS NULL. For mysql NULL is unknown value, therefore NULL != 1 is NULL instead of true. For detailed information you can look at mysql documentation
SELECT * FROM `test` WHERE `somevar` IS NULL OR `somevar`!=1
Related
CREATE TABLE abc
(
id INT NOT NULL,
class VARCHAR(10) NOT NULL,
division VARCHAR(1) NOT NULL,
dateOfxyz DATE NOT NULL,
PRIMARY KEY (id, class, division, dateOfxyz)
)
Now, I want to access id class and division part of this primary key in another table as the foreign key, can I do that? and If yes, then how?
I don't get your problem
In the referencing table, there must be an index where the foreign key columns are listed as the first columns in the same order. https://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html
MariaDB [sandbox]> drop table if exists t;
Query OK, 0 rows affected (0.03 sec)
MariaDB [sandbox]>
MariaDB [sandbox]> CREATE TABLE abc
-> (
-> id INT NOT NULL,
-> class VARCHAR(10) NOT NULL,
-> division VARCHAR(1) NOT NULL,
-> dateOfxyz DATE NOT NULL,
-> PRIMARY KEY (id, class, division, dateOfxyz)
-> );
ERROR 1050 (42S01): Table 'abc' already exists
MariaDB [sandbox]>
MariaDB [sandbox]> drop table if exists t;
Query OK, 0 rows affected, 1 warning (0.00 sec)
MariaDB [sandbox]> create table t
-> (id INT NOT NULL,
-> class VARCHAR(10) NOT NULL,
-> division VARCHAR(1) NOT NULL);
Query OK, 0 rows affected (0.03 sec)
MariaDB [sandbox]>
MariaDB [sandbox]> alter table t
-> add foreign key tfk1(id,class,division) references abc(id,class,division);
Query OK, 0 rows affected (0.12 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [sandbox]>
MariaDB [sandbox]> show create table t;
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t | CREATE TABLE `t` (
`id` int(11) NOT NULL,
`class` varchar(10) NOT NULL,
`division` varchar(1) NOT NULL,
KEY `tfk1` (`id`,`class`,`division`),
CONSTRAINT `tfk1` FOREIGN KEY (`id`, `class`, `division`) REFERENCES `abc` (`id`, `class`, `division`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
I want to perform transactional inserts , but i do not understand the problem because i couldnt see the error. I read carefully the mysql instructions for performing transactional procedure.
The problem is there is no return out header id, How do I mitigate this issue?
CREATE PROCEDURE `add_payment`(IN `transaction_no` VARCHAR(50),
IN `transaction_type_id` MEDIUMINT(8) UNSIGNED,
IN `distributor_details_id` MEDIUMINT(8) UNSIGNED,
IN `customer_id` INT(11) UNSIGNED,
IN `amount` DECIMAL(18,8),
IN `salesman_id` INT(11) UNSIGNED,
IN `created_datetime` DATETIME,
OUT `payment_header_id` INT(11) UNSIGNED)
BEGIN
DECLARE transaction_code_id INTEGER(11) UNSIGNED DEFAULT 0;
DECLARE transaction_x_payment_header_id INTEGER(11) UNSIGNED DEFAULT 0;
DECLARE payment_details_id INTEGER(11) UNSIGNED DEFAULT 0;
DECLARE user_id MEDIUMINT(8) UNSIGNED DEFAULT 0;
#
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SET payment_header_id = 0;
ROLLBACK ;
END;
START TRANSACTION;
# GET USER TO HAVE A REFERENCE WHOS DOING THIS
SET user_id = (SELECT user_id FROM salesman_x_user WHERE salesman_id = salesman_id);
# INSERT PAYMENT HEADER FIRST TO HAVE PAYMENT HEADER ID
INSERT INTO `payment_header` (`no` , `created_datetime`) VALUES(transaction_no , created_datetime);
SET payment_header_id = (SELECT LAST_INSERT_ID());
COMMIT;
END;
Avoid naming variables and parameters as columns of your tables.
See the following adapted example:
mysql> DROP TABLE IF EXISTS `payment_header`;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE IF NOT EXISTS `payment_header`(
-> `payment_header_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> `no` VARCHAR(50),
-> `created_datetime` DATETIME,
-> UNIQUE KEY (`no`)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER //
mysql> DROP PROCEDURE IF EXISTS `add_payment`//
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE PROCEDURE `add_payment` (
-> IN `_transaction_no` VARCHAR(50),
-> IN `_transaction_type_id` MEDIUMINT(8) UNSIGNED,
-> IN `_distributor_details_id` MEDIUMINT(8) UNSIGNED,
-> IN `_customer_id` INT(11) UNSIGNED,
-> IN `_amount` DECIMAL(18, 8),
-> IN `_salesman_id` INT(11) UNSIGNED,
-> IN `_created_datetime` DATETIME,
-> OUT `_payment_header_id` INT(11) UNSIGNED
-> )
-> BEGIN
-> DECLARE `transaction_code_id` INTEGER(11) UNSIGNED DEFAULT 0;
-> DECLARE `transaction_x_payment_header_id` INTEGER(11) UNSIGNED DEFAULT 0;
-> DECLARE `payment_details_id` INTEGER(11) UNSIGNED DEFAULT 0;
-> DECLARE `user_id` MEDIUMINT(8) UNSIGNED DEFAULT 0;
->
-> DECLARE EXIT HANDLER FOR SQLEXCEPTION
-> BEGIN
-> SET `_payment_header_id` = 0;
-> ROLLBACK;
-> END;
->
-> START TRANSACTION;
-> # GET USER TO HAVE A REFERENCE WHOS DOING THIS
-> /*SET `user_id` = (SELECT `user_id`
/*> FROM `salesman_x_user`
/*> WHERE `salesman_id` = `_salesman_id`);*/
->
-> # INSERT PAYMENT HEADER FIRST TO HAVE PAYMENT HEADER ID
-> INSERT INTO `payment_header` (`no` , `created_datetime`)
-> VALUES (`_transaction_no`, `_created_datetime`);
->
-> SET `_payment_header_id` = LAST_INSERT_ID();
-> COMMIT;
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> CALL `add_payment`(
-> '00000000000000000000000000000000000000000000000001',
-> NULL,
-> NULL,
-> NULL,
-> NULL,
-> NULL,
-> NOW(),
-> #`payment_header_id`
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT #`payment_header_id`;
+----------------------+
| #`payment_header_id` |
+----------------------+
| 1 |
+----------------------+
1 row in set (0.00 sec)
mysql> SELECT
-> `payment_header_id`,
-> `no`,
-> `created_datetime`
-> FROM
-> `payment_header`;
+-------------------+----------------------------------------------------+---------------------+
| payment_header_id | no | created_datetime |
+-------------------+----------------------------------------------------+---------------------+
| 1 | 00000000000000000000000000000000000000000000000001 | 2000-01-01 00:00:01 |
+-------------------+----------------------------------------------------+---------------------+
1 row in set (0.00 sec)
mysql> CALL `add_payment`(
-> '00000000000000000000000000000000000000000000000001',
-> NULL,
-> NULL,
-> NULL,
-> NULL,
-> NULL,
-> NOW(),
-> #`payment_header_id`
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT #`payment_header_id`;
+----------------------+
| #`payment_header_id` |
+----------------------+
| 0 |
+----------------------+
1 row in set (0.00 sec)
mysql> SELECT
-> `payment_header_id`,
-> `no`,
-> `created_datetime`
-> FROM
-> `payment_header`;
+-------------------+----------------------------------------------------+---------------------+
| payment_header_id | no | created_datetime |
+-------------------+----------------------------------------------------+---------------------+
| 1 | 00000000000000000000000000000000000000000000000001 | 2000-01-01 00:00:01 |
+-------------------+----------------------------------------------------+---------------------+
1 row in set (0.00 sec)
See db-fiddle.
I have a MySQL database with a table inventory with multiple triggers set up to capture changes in a second table inventory_history. I'm updating two of the fields (both in a single query, and in two separate queries), and the trigger consistently works on only one of the two fields (qty but not on last_sale).
Here is the troublesome query:
UPDATE inventory SET last_sale = 321, qty = 0 WHERE id = 123;
Alternately, these query combinations don't work either:
UPDATE inventory SET last_sale = 321 WHERE id = 123;
UPDATE inventory SET qty = 0 WHERE id = 123;
Here are the table constructs and triggers:
CREATE TABLE `inventory` (
`serial_no` varchar(255) DEFAULT NULL,
`qty` mediumint(9) DEFAULT NULL,
`partid` mediumint(9) unsigned DEFAULT NULL,
`last_sale` mediumint(9) unsigned DEFAULT NULL,
`date_created` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`id` mediumint(9) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
KEY `partid` (`partid`),
KEY `date_created` (`date_created`),
KEY `last_sale` (`last_sale`),
KEY `last_rma` (`last_return`),
KEY `last_purchase` (`last_purchase`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `inventory_history` (
`date` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`inventory_id` mediumint(9) unsigned NOT NULL,
`field_changed` enum('serial_no','qty','partid','last_sale','new') NOT NULL,
`changed_from` varchar(255) NOT NULL,
KEY `inventory_id` (`inventory_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TRIGGER `inv_new` AFTER INSERT ON `inventory`
FOR EACH ROW BEGIN
SET
#id = NEW.id,
#userid = NEW.userid,
#date = now();
INSERT INTO inventory_history VALUES (#date,#userid, #id, 'new', 'new');
END
//
DELIMITER ;
DROP TRIGGER IF EXISTS `inv_update`;
DELIMITER //
CREATE TRIGGER `inv_update` AFTER UPDATE ON `inventory`
FOR EACH ROW BEGIN
SET #userid = OLD.userid;
SET #inv_id = OLD.id;
IF (OLD.serial_no <> NEW.serial_no) THEN
INSERT INTO inventory_history VALUES (now(), #userid, #inv_id, 'serial_no', OLD.serial_no);
END IF;
IF (OLD.qty <> NEW.qty) THEN
INSERT INTO inventory_history VALUES (now(), #userid, #inv_id, 'qty', OLD.qty);
END IF;
IF (OLD.partid <> NEW.partid) THEN
INSERT INTO inventory_history VALUES (now(), #userid, #inv_id, 'partid', OLD.partid);
END IF;
IF (OLD.last_sale <> NEW.last_sale) THEN
INSERT INTO inventory_history VALUES (now(), #userid, #inv_id, 'last_sale', OLD.last_sale);
END IF;
END
//
DELIMITER ;
So again, the qty trigger works, but the last_sale does not.
I can't reproduce the problem:
mysql> DROP TABLE IF EXISTS `inventory_history`, `inventory`;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `inventory` (
-> `serial_no` varchar(255) DEFAULT NULL,
-> `qty` mediumint(9) DEFAULT NULL,
-> `partid` mediumint(9) unsigned DEFAULT NULL,
-> `last_sale` mediumint(9) unsigned DEFAULT NULL,
-> `date_created` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
-> `id` mediumint(9) unsigned NOT NULL AUTO_INCREMENT,
-> PRIMARY KEY (`id`),
-> KEY `partid` (`partid`),
-> KEY `date_created` (`date_created`),
-> KEY `last_sale` (`last_sale`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `inventory_history` (
-> `date` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-> `inventory_id` mediumint(9) unsigned NOT NULL,
-> `field_changed` enum('serial_no', 'qty', 'partid', 'last_sale', 'new') NOT NULL,
-> `changed_from` varchar(255) NOT NULL,
-> KEY `inventory_id` (`inventory_id`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.01 sec)
mysql> DELIMITER //
mysql> CREATE TRIGGER `inv_new` AFTER INSERT ON `inventory`
-> FOR EACH ROW
-> BEGIN
-> DECLARE `_id` MEDIUMINT UNSIGNED DEFAULT NEW.`id`;
-> DECLARE `_date` TIMESTAMP DEFAULT NOW();
-> INSERT INTO `inventory_history` VALUES (`_date`, `_id`, 'new', 'new');
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> DROP TRIGGER IF EXISTS `inv_update`;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> DELIMITER //
mysql> CREATE TRIGGER `inv_update` AFTER UPDATE ON `inventory`
-> FOR EACH ROW
-> BEGIN
-> DECLARE `_inv_id` MEDIUMINT UNSIGNED DEFAULT OLD.`id`;
->
-> IF (OLD.`serial_no` <> NEW.`serial_no`) THEN
-> INSERT INTO `inventory_history` VALUES (NOW(), `_inv_id`, 'serial_no', OLD.`serial_no`);
-> END IF;
->
-> IF (OLD.`qty` <> NEW.`qty`) THEN
-> INSERT INTO `inventory_history` VALUES (NOW(), `_inv_id`, 'qty', OLD.`qty`);
-> END IF;
->
-> IF (OLD.`partid` <> NEW.`partid`) THEN
-> INSERT INTO `inventory_history` VALUES (NOW(), `_inv_id`, 'partid', OLD.`partid`);
-> END IF;
->
-> IF (OLD.`last_sale` <> NEW.`last_sale`) THEN
-> INSERT INTO `inventory_history` VALUES (NOW(), `_inv_id`, 'last_sale', OLD.`last_sale`);
-> END IF;
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> INSERT INTO `inventory`
-> (`serial_no`, `qty`, `partid`, `last_sale`)
-> VALUES
-> ('1', 0, 0, 321);
Query OK, 1 row affected (0.00 sec)
mysql> SELECT
-> `serial_no`,
-> `qty`,
-> `partid`,
-> `last_sale`,
-> `date_created`,
-> `id`
-> FROM
-> `inventory`;
+-----------+------+--------+-----------+---------------------+----+
| serial_no | qty | partid | last_sale | date_created | id |
+-----------+------+--------+-----------+---------------------+----+
| 1 | 0 | 0 | 321 | 2016-11-15 00:00:51 | 1 |
+-----------+------+--------+-----------+---------------------+----+
1 row in set (0.00 sec)
mysql> SELECT
-> `date`,
-> `inventory_id`,
-> `field_changed`,
-> `changed_from`
-> FROM
-> `inventory_history`;
+---------------------+--------------+---------------+--------------+
| date | inventory_id | field_changed | changed_from |
+---------------------+--------------+---------------+--------------+
| 2016-11-15 00:00:51 | 1 | new | new |
+---------------------+--------------+---------------+--------------+
1 row in set (0.00 sec)
mysql> UPDATE `inventory`
-> SET `last_sale` = 0, `qty` = 321
-> WHERE `id` = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT
-> `date`,
-> `inventory_id`,
-> `field_changed`,
-> `changed_from`
-> FROM
-> `inventory_history`;
+---------------------+--------------+---------------+--------------+
| date | inventory_id | field_changed | changed_from |
+---------------------+--------------+---------------+--------------+
| 2016-11-15 00:00:51 | 1 | new | new |
| 2016-11-15 00:00:51 | 1 | qty | 0 |
| 2016-11-15 00:00:51 | 1 | last_sale | 321 |
+---------------------+--------------+---------------+--------------+
3 rows in set (0.00 sec)
mysql> SELECT
-> `serial_no`,
-> `qty`,
-> `partid`,
-> `last_sale`,
-> `date_created`,
-> `id`
-> FROM
-> `inventory`;
+-----------+------+--------+-----------+---------------------+----+
| serial_no | qty | partid | last_sale | date_created | id |
+-----------+------+--------+-----------+---------------------+----+
| 1 | 321 | 0 | 0 | 2016-11-15 00:00:51 | 1 |
+-----------+------+--------+-----------+---------------------+----+
1 row in set (0.00 sec)
Days later, turns out to be a simple but profound explanation (isn't it always?).
The trigger statement I used above was:
IF (OLD.last_sale <> NEW.last_sale) THEN
INSERT INTO inventory_history VALUES (now(), #userid, #inv_id, 'last_sale', OLD.last_sale);
END IF;
The problem with this statement is that it doesn't capture a value change from NULL to 0, for example. It only captures a value to another value. So I needed to ADD a second statement for the NULL scenarios:
IF (OLD.last_sale IS NULL AND NEW.last_sale IS NOT NULL) THEN
INSERT INTO inventory_history VALUES (now(), #userid, #inv_id, 'last_sale', OLD.last_sale);
END IF;
And all the world is right. :)
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?
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.