当前位置: 首页 > 面试题库 >

如何检查INSERT在存储功能中是否运行良好?

顾学真
2023-03-14
问题内容

我正在创建一个存储函数,该函数应该在表中插入新行。该表中还有一个唯一列。

如何检查一切是否顺利,是否确实插入了行?

我如何才能准确地检查是否找到此唯一列(例如-尝试添加重复值)?


问题答案:

您可以检查LAST_INSERT_ID()函数和INSERT IGNORE。

如果INSERT IGNORE成功,则返回主键。让我们创建一个带有自动递增主键和名称上的唯一键的表。

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;

这是正在运行的示例:

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>

如上例所示,您可以检查函数的返回值。返回值非零表示INSERT IGNORE运行良好。返回值为零表示键重复,而没有在mysqld中引入错误号。

这种方法的缺点是,由于在密钥重复的情况下插入INSERT IGNORE的尝试失败,因此您无法返回并使用ID 2和ID 4。

让我们尝试另一个示例,该示例使用INSERT而不使用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;

结果如下:

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>

在此示例中,如果INSERT正常,则存储的函数将返回0,并在名称上带有重复键的情况下返回1。优势?不会浪费auto_increment的ID号。劣势?每次执行SELECT语句以检查表中已经存在的名称。

您可以选择要使用哪种方式处理重复键。第一种方法使mysqld处理INSERT
IGNORE的条件。第二种方法具有存储功能,该功能首先在INSERT之前检查重复密钥。



 类似资料:
  • 问题内容: 如何检查存储过程或查询是否仍在SQL Server中运行? 主意 我曾经想过要在过程开始时在哪里写日志,并在过程结束时将日志删除。 缺陷: 使用过程监控器 我希望能有一个可以合并为一个存储过程的解决方案和/或,作为输入,所以使用SQL Server的界面将无法正常工作跟踪程序或解决方案。 更新#1 用法示例: 该过程应该像 并在运行时(20秒内)返回true,然后在函数失败或系统重新启

  • 问题内容: 在我的代码中的某些情况下,只有在定义了该函数的情况下,我最终才调用该函数,否则我不应该调用该函数。我怎样才能做到这一点? 提出此问题的另一种方法可能是:如何确定函数是否在运行时定义,如果是,则调用。 问题答案: 尽管其他答复是有用的建议(,函数指针等),但是您 不能编译 引用不存在的函数的C ++代码。至少必须 声明 函数;如果不是,您的代码将无法编译。如果没有任何内容(编译单元,某些

  • 问题内容: 我在我的项目中使用JobService。运行良好。但有时服务停止了。它不会再次重新启动。因此,如果没有运行,我将尝试分层JobService。但是我不知道如何检查JobService是否已经运行。请让我知道如何检查JobService是否正在运行。 我的工作服务课程: 我的实用程序类: 开始: 停止: 问题答案: 我找到了解决方案。 使用此方法,我们可以检查jobService是否正在

  • 问题内容: 如何检查Java中是否存在类的方法?将一个声明是好的做法呢? 问题答案: 我假设您要检查该方法。 您可以尝试以下方法: 这将不起作用,因为该方法将在编译时解决。 您确实需要使用反射。而且,如果您可以访问要调用的方法的源代码,则最好使用要调用的方法创建一个接口。 [更新]附加信息是:有一个接口可能存在两个版本,一个是旧版本(不包含所需方法),一个是新版本(具有所需方法)。基于此,我提出以

  • 问题内容: 我需要帮助检查数据库中是否存在行。就我而言,该行包含一个电子邮件地址。我得到结果: 这是我当前正在使用的代码: 有没有更好的方法来检查MySQL中是否存在行(在我的情况下,检查MySQL中是否存在电子邮件)? 问题答案: 以下是经过尝试,测试和证明的检查行是否存在的方法。 (其中一些我自己使用,或者过去使用过)。 编辑: 我在使用两次的语法中犯了一个先前的错误。请查阅修订版本。 即:

  • 我需要帮助检查数据库中是否存在行。在我的例子中,该行包含一个电子邮件地址。我得到的结果是: 这是我目前使用的代码: 有没有更好的方法来检查MySQL中是否存在行(在我的例子中,检查MySQL中是否存在电子邮件)?