0

这个问题是我之前的问题的顺序,要求在删除一行时更新同一张表。

我可以使用存储过程而不是触发器或嵌套查询 来编写两个解决方案。

两者都使用辅助函数my_signal(msg)

Employee表中删除员工的存储过程。

  • 拳头解决方案:使用UPDATE表中的行,无需连接操作
CREATE PROCEDURE delete_employee(IN dssn varchar(64))
BEGIN
    DECLARE empDesignation varchar(128);
    DECLARE empSsn         varchar(64);
    DECLARE empMssn        varchar(64);
     SELECT SSN, designation, MSSN  INTO empSsn, empDesignation, empMssn 
     FROM Employee 
     WHERE SSN = dssn;

   IF (empSsn IS NOT NULL) THEN
    CASE       
           WHEN empDesignation = 'OWNER' THEN 
               CALL my_signal('Error: OWNER can not deleted!');

           WHEN empDesignation = 'WORKER' THEN 
            DELETE FROM Employee WHERE SSN = empSsn;               

           WHEN empDesignation = 'BOSS' THEN 
               BEGIN 
                   UPDATE Employee
                   SET MSSN = empMssn
                   WHERE MSSN = empSsn;

                DELETE FROM Employee WHERE SSN = empSsn;                   

               END;
    END CASE;
   ELSE 
               CALL my_signal('Error: Not a valid row!');
   END IF;
END//  
  • 第二种解决方案:正如我在上一个问题中建议的那样,使用INNER JOIN
CREATE PROCEDURE delete_employee(IN dssn varchar(64))
BEGIN
    DECLARE empDesignation varchar(128);
    DECLARE empSsn         varchar(64);
    DECLARE empMssn        varchar(64);
      SELECT SSN, designation, MSSN  INTO empSsn, empDesignation, empMssn 
      FROM Employee 
      WHERE SSN = dssn;

   IF (empSsn IS NOT NULL) THEN
       IF (empDesignation = 'OWNER') THEN 
        CALL my_signal('Error: OWNER can not deleted!');
       END IF;

       UPDATE `Employee` A INNER JOIN `Employee` B ON A.SSN= B.MSSN
       SET B.MSSN = A.MSSN WHERE A.SSN = empSsn;

       DELETE FROM `Employee` WHERE SSN = empSsn;
   ELSE 
       CALL my_signal('Error: Not a valid row!');
   END IF;    
END//

我在这里读到,使用 join 对于 Efficient SELECT 是有效的。但是我的问题只包括一个表,我觉得我的解决方案(第一个)比第二个更有效,因为 join 会比较消耗内存。

Employee table如果足够大,请建议我哪个更好,更有效。哪个更适合我?原因

编辑: 我检查了只包含 7 行的小表,两种解决方案都需要相同的时间。

mysql> CALL delete_employee(4);
Query OK, 1 row affected (0.09 sec)

我知道 SQL 函数的行为是不确定的,因为表启发式。哪个选择更好?如果您有一些想法,可以进一步优化查询。

4

1 回答 1

0

经过一段时间的思考,我几乎可以肯定它没有什么不同,第一个解决方案可能会稍微慢一些,但在一个不可测量的维度上。

第一个意图是,第一个解决方案更快,因为您首先通过 id 获取数据并仅在必要时更新。

但是 MySQL 在内部没有在UPDATE .. JOIN语句中做任何其他事情,只是在内部,因此可能也更有效。

您的第一个解决方案没有捕获默认情况 - 如果我既没有得到,又会发生WORKER什么BOSS

此外,您的执行时间(0.09 秒)非常高,这无法用我目前对您的数据库的了解来解释。

你有没有设置任何索引?

编辑:

查看您在此处发布的表结构后, 我对结构本身提出了一些改进建议。

1.int存储时使用类型integer values。数据库可以更高效地处理整数方式

2.为什么要SSN自己生成?在添加新员工时,使用auto_incrementon thePRIMARY KEY更容易处理并为您节省大量工作

ALTER TABLE `Employee`
    CHANGE `SSN` `SSN` int(11) NOT NULL AUTO_INCREMENT ,
    CHANGE `MSSN` `MSSN` int(11) DEFAULT NULL,
    ADD KEY `KEY_Employee_MSSN` ( `MSSN` );

3.您是否使用名称进行查找?如果是这样,它也需要是唯一的

ALTER TABLE `Employee`
    ADD UNIQUE KEY `UNI_KEY_Employee` ( `name` );

4.你们有固定的指定范围吗?enum 强制输入为定义的值之一

ALTER TABLE `Employee`
    CHANGE `designation` `designation` ENUM( 'BOSS', 'WORKER' ) NOT NULL DEFAULT 'WORKER',
    ADD KEY `KEY_Employee_designation` ( `designation` );

最终结构

mysql> EXPLAIN `Employee`;

+-------------+-----------------------+------+-----+---------+----------------+
| Field       | Type                  | Null | Key | Default | Extra          |
+-------------+-----------------------+------+-----+---------+----------------+
| SSN         | int(11)               | NO   | PRI | NULL    | auto_increment |
| name        | varchar(64)           | YES  | UNI | NULL    |                |
| designation | enum('BOSS','WORKER') | NO   | MUL | WORKER  |                |
| MSSN        | int(11)               | YES  | MUL | NULL    |                |
+-------------+-----------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
于 2012-11-27T16:16:51.183 回答