2012-11-21 3 views
12

In meiner Datenbank habe ich eine Tabelle Employee, die rekursive Verein hat (Mitarbeiter Chef anderer Mitarbeiter sein kann):Wie aktualisiert die gleiche Tabelle beim Löschen in MYSQL?

create table if not exists `employee` (

    `SSN` varchar(64) not null, 
    `name` varchar(64) default null, 
    `designation` varchar(128) not null, 
    `MSSN` varchar(64) default null, 
    primary key (`ssn`), 
    constraint `fk_manager_employee` foreign key (`mssn`) references employee(ssn) 

) engine=innodb default charset=latin1; 

mysql> describe Employee; 
+-------------+--------------+------+-----+---------+-------+ 
| Field  | Type   | Null | Key | Default | Extra | 
+-------------+--------------+------+-----+---------+-------+ 
| SSN   | varchar(64) | NO | PRI | NULL |  | 
| name  | varchar(64) | YES |  | NULL |  | 
| designation | varchar(128) | NO |  | NULL |  | 
| MSSN  | varchar(64) | YES | MUL | NULL |  | 
+-------------+--------------+------+-----+---------+-------+ 
4 rows in set (0.00 sec) 

Dann fügt: Jetzt

mysql> insert into Employee values 
    -> ("1", "A", "OWNER", NULL), 
    -> ("2", "B", "BOSS", "1"), 
    -> ("3", "C", "WORKER", "2"), 
    -> ("4", "D", "BOSS", "2"), 
    -> ("5", "E", "WORKER", "4"), 
    -> ("6", "F", "WORKER", "1"), 
    -> ("7", "G", "WORKER", "4") 
    -> ; 
Query OK, 7 rows affected (0.02 sec) 
Records: 7 Duplicates: 0 Warnings: 0 

Ich habe folgende hierarchische Beziehung (Besitzer> Chef> Arbeiter) unter den Zeilen in der Tabelle:

 A 
    /\ 
    B F 
/\ 
c D 
    /\ 
    G E 

Es folgt Select-Anweisung für die Tabelle:

mysql> SELECT * FROM Employee; 
+-----+------+-------------+------+ 
| SSN | name | designation | MSSN | 
+-----+------+-------------+------+ 
| 1 | A | OWNER  | NULL | 
| 2 | B | BOSS  | 1 | 
| 3 | C | WORKER  | 2 | 
| 4 | D | BOSS  | 2 | 
| 5 | E | WORKER  | 4 | 
| 6 | F | WORKER  | 1 | 
| 7 | G | WORKER  | 4 | 
+-----+------+-------------+------+ 
7 rows in set (0.00 sec) 

Nun, ich möchte eine Beschränkung auferlegen wie: If any employee (BOSS) deleted then new BOSS of workers under him become immediate BOSS of deleted employee (Old BOSS). z.B. Wenn ich lösche, dann B Werde BOSS von G und E.

Dafür habe ich geschrieben auch ein Trigger- wie folgt:

mysql> DELIMITER $$ 
mysql>  CREATE 
    ->  TRIGGER `Employee_before_delete` BEFORE DELETE 
    ->   ON `Employee` 
    ->   FOR EACH ROW BEGIN 
    ->   UPDATE Employee 
    ->   SET MSSN=old.MSSN 
    ->   WHERE MSSN=old.MSSN; 
    ->  END$$ 
Query OK, 0 rows affected (0.07 sec) 

mysql>  DELIMITER ; 

Aber wenn ich eine Löschung durchführen:

mysql> DELETE FROM Employee WHERE SSN='4'; 
ERROR 1442 (HY000): Can't update table 'Employee' in stored function/trigger 
because it is already used by statement which invoked this stored 
function/trigger. 

ich learn here dass this trigger is not possible weil In MySQL triggers can't manipulate the table they are assigned to.

Gibt es einige anderen möglichen Weg, dies zu tun? Ist es möglich, Nested Query zu verwenden? Kann mir jemand eine andere Methode vorschlagen? Ein Vorschlag wäre genug, sollte aber effizient sein.

EDIT:
ich Antworten bekommen: Statt Trigger ein stored procedure oder two consecutive queries möglich. First und second.

Die Lösung, die ich für dieses Problem wie unten beschrieben, funktioniert gut!:

  • A eine Funktion Helfersignal als ich für MYSQL version older then 5.5 schreibe.

DELIMITER //

CREATE PROCEDURE `my_signal`(in_errortext VARCHAR(255)) 
BEGIN 
    SET @sql=CONCAT('UPDATE `', in_errortext, '` SET x=1'); 
    PREPARE my_signal_stmt FROM @sql; 
    EXECUTE my_signal_stmt; 
    DEALLOCATE PREPARE my_signal_stmt; 
END// 
  • Eine Stored Procedure Mitarbeiter aus Employee Tabelle zu löschen.
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// 

DELIMITER;

+1

Können Sie Folgendes versuchen? Es sieht eher zu einfach für Ihre Anforderung speziell im Hinblick auf eine dynamische Deletion ... 'Update Employee' ' set MSSN = (wählen MSSN von employee' 'wo ssn = '4');' 'löschen von Mitarbeiter wo ssn = 4;' – bonCodigo

+0

@bonCodigo: Sie meinen zwei aufeinander folgende Abfrage zum Löschen. Kann in Betracht gezogen werden ... Aber ich muss darüber nachdenken - Danke! –

+1

Yeah zwei aufeinander folgende Abfragen. Es scheint auch, dass EntityFramework in SQL Server Repository-Muster bietet - es könnte Ihnen ermöglichen, die Löschfunktion des Repositorys über eine gespeicherte Prozedur rekursiv zu machen. Ich habe es nicht persönlich gemacht. Vielleicht könntest du das gleiche hier nachahmen. Interessante Frage +1 – bonCodigo

Antwort

4

Verwenden Sie ein stored procedure:

UPDATE b 
    SET b.mssn = a.mssn 
    FROM EMPLOYEE a 
    JOIN EMPLOYEE b ON b.mssn = a.ssn 
WHERE a.ssn = @deletedBoss 

DELETE FROM employee WHERE ssn = @deletedBoss 

Mit einer gespeicherten Prozedur, können Sie einfach die Zeilen löschen, die Sie möchten, und danach, die gleiche Tabelle aktualisieren. Das sollte die Fehlermeldung verhindern.

+0

Sie meinen statt Trigger, sollte ich Prozedur aufrufen, die beide löschen und aktualisieren ... Ich würde versuchen.-danke –

+0

Ja, Sie können so viele Anweisungen ausführen, wie Sie möchten innerhalb einer gespeicherten Prozedur. Sie können jede CRUD-Anweisung für alle Tabellen innerhalb einer einzigen gespeicherten Prozedur ausführen. Und wenn die Antwort hilft, upvote es. Vielen Dank. –

+1

@GrijeshChauhan: Anstatt meine eigene Post, habe ich nur Code hinzugefügt. –

0

Anstatt ein hartes Löschen durchzuführen, führen Sie ein weiches Löschen durch. Fügen Sie die Spalte is_deleted hinzu und setzen Sie sie auf 1, wenn Sie die Zeile löschen möchten. Erstellen Sie einen After_update-Trigger für die Tabelle.

Ich bin nicht sicher, dass Sie die gleiche Tabelle für after_ {insert, delete, update} aktualisieren können. Bitte überprüfen Sie diese

+0

Wir können die Tabelle im Trigger, auf dem der Trigger aufgerufen wird, nicht aktualisieren! –

+0

Dies ist ein Vorschlag, keine Antwort. – Pacerier