2014-12-30 10 views
5

Hi uno sviluppatore ha chiesto di aggiungere una colonna su una tabella che avrà un valore predefinito di 'N', tuttavia se la voce ha un id = 3, allora il valore predefinito di questa colonna dovrebbe essere 'Y', è comunque possibile ottenerlo in oracolo?Orace: valore della colonna predefinito basato su un filtro

+0

Generalmente gestisco tali cose dal lato dell'applicazione. semplicemente 'column = 'N'; if (id == 3) then column = 'Y'; ----- salva la riga nel DB ------ '. e se nel DB sono presenti righe esistenti, aggiornare semplicemente la colonna con un'istruzione 'case when' per le righe esistenti. –

+1

forse aggiungi un trigger per questo durante l'inserimento? –

+1

'VIRTUAL column' con una funzione' DECODE' è tutto ciò che serve. –

risposta

0

approccio 11g

Da Oracle 11g in su, si potrebbe fare questo in un unico passaggio utilizzando VIRTUAL columns.

Test case

SQL> CREATE TABLE tab_default (
    2 ID   NUMBER, 
    3 flag varchar2(1) GENERATED ALWAYS AS (decode(id, 3, 'Y', 'N')) VIRTUAL 
    4 ); 

Table created. 

SQL> 
SQL> INSERT INTO tab_default (ID) VALUES (1); 

1 row created. 

SQL> INSERT INTO tab_default (ID) VALUES (3); 

1 row created. 

SQL> INSERT INTO tab_default (ID) VALUES (10); 

1 row created. 

SQL> SELECT * FROM tab_default; 

     ID F 
---------- - 
     1 N 
     3 Y 
     10 N 

SQL> 

Quindi, la funzione DECODE nella dichiarazione colonna di VIRTUAL gestisce il requisito per voi.

approccio 10g

Si potrebbe soddisfare il requisito usando -

  1. DEFAULT valore
  2. AFTER INSERT TRIGGER ogni volta id = 3

Creare la tabella di avere DEFAULT valore come ' N'. Attiva il trigger solo quando viene inserita una nuova riga con valore nella colonna id = 3, in modo che il trigger aggiorni il valore su "Y". Altrimenti per tutti gli altri casi il valore predefinito sarebbe 'N'.

+0

perché si desidera utilizzare un trigger AFTER anziché un trigger BEFORE? –

+0

Poiché un trigger successivo assicura almeno che la transazione sia stata anticipata. Se dipendi da prima del trigger e apporti le modifiche in base a ciò, NON PUOI essere una garanzia. Non farà molta differenza, tuttavia, in questi casi preferisco un after trigger. A proposito, non sono un grande fan degli inneschi perché sono un'azione di un effetto, quindi un effetto collaterale. Ma, in questo caso, se qualcuno non è in '11g', allora è l'unico modo. E questa è la ragione principale per cui ho modificato la mia risposta e spostato l'approccio '11g' al di sopra dell'approccio' 10g'trigger. –

0

Dopo l'aggiunta di nuova colonna alla tabella è possibile inserire il valore nella colonna usando sotto query:

update table_name set column_name = (case when id = 3 then 'Y' else 'N' end);  

Al di inserimento di nuovi record si può usare sotto approccio:
1) Decidere di colonna al momento della creando la query di inserimento, è possibile aggiungere una logica per tale quando si crea una query.
2) Creare un trigger nel database che dovrebbe aggiornare il valore della colonna dopo aver inserito una nuova riga nella tabella.

0

Questo è un design di database molto scarso. Non rispetta la forma normale del database relazionale. Suggerisco di mantenere la tabella così com'è e creare una nuova vista sul tavolo con una colonna aggiuntiva che viene calcolata utilizzando DECODE o CASE WHEN ...

+0

Intendi design scadente? Non alimentazione ... – user2672165

+0

Sì design scadente. Ho modificato il testo – Charmi

+0

Non tutte le applicazioni possono essere risolte durante la notte. Ed è per questo che abbiamo bisogno di soluzioni alternative per un periodo temporaneo fino a quando non viene trovata e implementata una soluzione permanente. –

0

Sono d'accordo con i commentatori che hanno menzionato che questo non è un buon progettazione del database. Detto questo, fare compromessi con la progettazione del database non è insolito nelle situazioni reali.

Non sono sicuro che una colonna virtuale sia ciò che si desidera. L'OP ha chiesto un modo per avere un valore predefinito; una colonna virtuale funziona in modo diverso rispetto a un vincolo predefinito (ad esempio, con un vincolo predefinito possiamo inserire un valore diverso da quello predefinito nella colonna. La migliore soluzione da adottare potrebbe essere l'utilizzo di un trigger per impostare il valore "predefinito":

CREATE OR REPLACE TRIGGER mytrigger 
    BEFORE INSERT ON mytable FOR EACH ROW 
    WHEN (new.mycolumn IS NULL) 
BEGIN 
    SELECT DECODE(id, 3, 'Y', 'N') INTO :new.mycolumn FROM dual; 
END; 
/

Un trigger funzionerà anche se si sta utilizzando Oracle 10g o 11g (entrambi i quali hai codificato).

Spero che questo aiuti.

+0

Se si utilizza ': new.mycolumn: = CASE: new.id QUANDO 3 THEN 'Y' ELSE 'N' END;' invece di 'SELECT' si salva il costo di salto per il motore PL/SQL in SQL motore e ritorno solo per eseguire il test IF. Inoltre, non credo che il tuo riferimento a 'id' rientri nello scope senza': new' di fronte. Gradirei anche un commento sull'uso di ': old' piuttosto che': new' qui. – Unoembre

+0

Grazie per il commento, penso che tu abbia ragione su tutto ciò che hai menzionato. Si potrebbe anche usare 'DECODE (: new.id, 3, 'Y', 'N')' piuttosto che 'CASE' ecc. –

+0

Ricorda che' DECODE' è valido solo in SQL non in PL/SQL. CASE è valido in entrambi. – Unoembre