2012-11-21 19 views
12

nel mio database ho una tabella Employee che ha un'associazione ricorsiva (un dipendente può essere capo di altro dipendente):Come aggiornare la stessa tabella alla cancellazione 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) 

inserisce Poi:

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 

Ora Ho la seguente relazione gerarchica (proprietario> capo> lavoratore) tra le righe della tabella:

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

seguito è Select per la tabella:

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) 

ora, voglio imporre un vincolo simile: If any employee (BOSS) deleted then new BOSS of workers under him become immediate BOSS of deleted employee (Old BOSS). per esempio. Se elimino D allora B diventa BOSS di G e E.

Per questo ho anche scritto un trigger come segue:

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 ; 

ma quando ho eseguire alcune eliminazione:

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. 

ho learn here che this trigger is not possible perché In MySQL triggers can't manipulate the table they are assigned to.

C'è qualche altro modo possibile per fare questo ? È possibile utilizzare Nested Query? Qualcuno può suggerirmi un altro metodo? Un suggerimento sarebbe sufficiente ma dovrebbe essere efficiente.

EDIT:
ho ottenuto risposte: Invece di innescare un stored procedure o two consecutive queries è possibile. First e second.

La soluzione ho scritto per questo problema come di seguito, Funzionante bene!:

  • A un segnale di aiuto funzione di come sto scrivendo per MYSQL version older then 5.5.

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// 
  • una stored procedure per eliminare dipendente da Employee tabella.
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

Puoi provare quanto segue? Sembra un po 'troppo semplice per il vostro requisito speciale in termini di avere una delezione dinamica ... 'aggiornamento Employee' ' set MSSN = (SELECT MSSN da employee' 'dove ssn = '4');' 'delete from employee where ssn = 4;' – bonCodigo

+0

@bonCodigo: intendi due query consecutive per l'eliminazione. Può essere considerato ... Ma devo pensare a questo-Grazie! –

+1

Sì, due domande consecutive. Sembra anche che EntityFramework nel server sql fornisca Pattern di Repository - potrebbe consentire di rendere ricorsiva la funzione di cancellazione del repository tramite una stored procedure. Non l'ho fatto personalmente. Forse potresti imitare lo stesso qui. Interessante domanda +1 – bonCodigo

risposta

4

Utilizzare un 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 

Con una stored procedure, è possibile semplicemente eliminare le righe che si desidera, e dopo che, aggiornare allo stesso tavolo. Questo dovrebbe impedire il messaggio di errore.

+0

Vuoi dire invece di Trigger, dovrei chiamare la procedura che cancella e aggiorna entrambi ... Vorrei provare.-grazie –

+0

Sì, è possibile eseguire tutte le istruzioni che si desidera all'interno di una stored procedure. È possibile eseguire qualsiasi istruzione CRUD su qualsiasi tabella all'interno di una singola stored procedure. E se la risposta ti aiuta, fallo di nuovo. Grazie. –

+1

@GrijeshChauhan: Piuttosto che pubblicare il mio, ho appena aggiunto il codice. –

0

Invece di eseguire un'eliminazione definitiva, eseguire un'eliminazione software. Aggiungi la colonna is_deleted e impostala su 1 se desideri eliminare la riga. Crea un trigger after_update sulla tabella.

DELIMITER $$ 
    CREATE 
    TRIGGER `Employee_after_update` AFTER UPDATE 
     ON `Employee` 
     FOR EACH ROW BEGIN 
     UPDATE Employee 
     ............... 
     WHERE NEW.is_deleted=1; 
     DELETE FROM Employee WHERE NEW.is_deleted=1 
    END$$ 

Non sono sicuro di poter aggiornare la stessa tabella per after_ {inserire, eliminare, aggiornare}. Si prega di controllare questo

+0

Impossibile aggiornare la tabella nel trigger su cui viene chiamato il trigger! –

+0

Questo è un suggerimento, non una risposta. – Pacerier