Welcome To Oracle 12c
Welcome To Oracle 12c
Architettura
SQL
PL/SQL
C come Cloud
http://oracleitalia.wordpress.com
ISBN 978-1-291-82092-8
2
Sommario
Sommario......................................................................................................... 3
Introduzione ..................................................................................................... 9
1 Architettura di Oracle ............................................................................ 11
1.1 Istanza e database......................................................................... 11
1.2 Istanza - Processi di base .............................................................. 11
1.2.1 PMON Process Monitor ...................................................... 12
1.2.2 SMON System Monitor ....................................................... 12
1.2.3 DBWn Database Writer ...................................................... 12
1.2.4 LGWR Log Writer................................................................ 12
1.2.5 CKPT Checkpoint ............................................................... 12
1.3 Istanza - Strutture di memoria ....................................................... 12
1.3.1 SGA System Global Area ................................................... 12
1.3.2 PGA Program Global Area ................................................. 13
1.4 Database - Strutture per la memorizzazione dei dati .................... 13
1.4.1 Datafile e blocchi.................................................................... 13
1.4.2 Extent ..................................................................................... 14
1.4.3 Tablespace ............................................................................ 14
1.4.4 Segment ................................................................................. 15
1.5 Database - File di controllo e di log ............................................... 15
1.5.1 Il control file ............................................................................ 15
1.5.2 I Redo Log file ........................................................................ 15
2 Installazione .......................................................................................... 17
3 Operazioni preliminari ........................................................................... 19
3.1 Avviare ed arrestare Oracle ........................................................... 19
3.1.1 Startup ................................................................................... 20
3.1.2 Shutdown ............................................................................... 20
3.2 Connettersi al database ................................................................. 21
3.2.1 Utenti e schemi ...................................................................... 21
3.2.2 Connettersi dal server dove installato il db ......................... 22
3.2.3 Connettersi da un client remoto ............................................. 22
3.2.4 Creare un nuovo utente ......................................................... 31
4 SQL*Plus e SQL Developer .................................................................. 32
4.1 SQL*Plus ....................................................................................... 32
4.1.1 Perch ancora SQL*Plus ....................................................... 33
4.1.2 Personalizzare SQL*Plus (Windows) .................................... 33
3
4.1.3 Parametri e comandi di SQL*Plus ......................................... 36
4.1.4 Scrittura e modifica di unistruzione SQL ............................... 38
4.1.5 esecuzione di uno script SQL ................................................ 41
4.1.6 Cambio del prompt SQL ........................................................ 42
4.2 SQL Developer .............................................................................. 43
4.2.1 Avvio di SQL Developer ......................................................... 43
4.2.2 Parametri e comandi di SQL Developer ................................ 45
5 Oggetti del DB ....................................................................................... 46
5.1 Il dizionario dati .............................................................................. 46
5.2 Tabelle ........................................................................................... 49
5.2.1 Colonne di una tabella ........................................................... 50
5.2.2 Constraint ............................................................................... 51
5.3 Indici ............................................................................................... 52
5.3.1 Indici B-Tree ........................................................................... 53
5.3.2 Indici Bitmap........................................................................... 54
5.3.3 Pi indici sullo stesso insieme di colonne .............................. 54
5.4 IOT ................................................................................................. 55
5.5 Cluster di tabelle ............................................................................ 56
5.6 Viste ............................................................................................... 56
5.6.1 Check option constraint ......................................................... 57
5.7 Viste materializzate ........................................................................ 57
5.8 Sequenze ....................................................................................... 58
5.9 Sinonimi ......................................................................................... 58
5.10 Database link ................................................................................. 59
5.11 Oggetti PL/SQL .............................................................................. 59
5.11.1 Procedure............................................................................... 59
5.11.2 Funzioni.................................................................................. 59
5.11.3 Package ................................................................................. 59
5.11.4 Trigger .................................................................................... 60
5.12 Estensioni Object-Oriented ............................................................ 60
5.13 XML DB .......................................................................................... 60
6 CASE STUDY ....................................................................................... 61
6.1 Progettazione ................................................................................. 61
6.2 Il database desempio .................................................................... 61
6.2.1 Tabelle ................................................................................... 62
6.2.2 Dati ......................................................................................... 64
6.3 SCOTT/TIGER ............................................................................... 65
7 SQL ....................................................................................................... 67
7.1 Tipi di dato ..................................................................................... 68
7.1.1 Dati alfanumerici .................................................................... 69
7.1.2 Numeri.................................................................................... 70
7.1.3 Date ed orari .......................................................................... 71
7.1.4 Dati binari ............................................................................... 71
7.2 Comandi DDL ................................................................................ 72
7.2.1 CREATE................................................................................. 72
7.2.2 ALTER.................................................................................... 91
7.2.3 RENAME .............................................................................. 101
7.2.4 DROP ................................................................................... 102
7.2.5 TRUNCATE.......................................................................... 104
4
7.2.6 PURGE ................................................................................ 107
7.2.7 FLASHBACK TABLE ........................................................... 108
7.3 Comandi DML .............................................................................. 109
7.3.1 Valori fissi ............................................................................. 109
7.3.2 INSERT ................................................................................ 110
7.3.3 UPDATE .............................................................................. 124
7.3.4 DELETE ............................................................................... 126
7.3.5 MERGE ................................................................................ 127
7.3.6 Gestione degli errori in SQL con LOG ERRORS ................ 131
7.4 SELECT, il comando di ricerca .................................................... 137
7.4.1 Proiezioni ............................................................................. 137
7.4.2 La tabella DUAL ................................................................... 140
7.4.3 Pseudo colonne ................................................................... 141
7.4.4 Selezioni .............................................................................. 143
7.4.5 Ordinamento ........................................................................ 160
7.4.6 Raggruppamenti .................................................................. 164
7.4.7 Tornando su ROWNUM ....................................................... 173
7.4.8 Le clausole PIVOT ed UNPIVOT ......................................... 175
7.4.9 Query gerarchiche ............................................................... 179
7.4.10 Paginazione dei record estratti in SQL ................................ 187
7.4.11 Pattern matching di righe ..................................................... 191
7.4.12 La clausola MODEL ............................................................. 195
7.5 Manipolazione dei dati ................................................................. 206
7.5.1 Operatore di concatenazione ............................................... 206
7.5.2 Operatori aritmetici............................................................... 207
7.5.3 Funzioni sulle stringhe ......................................................... 208
7.5.4 Funzioni sui numeri .............................................................. 218
7.5.5 Funzioni sulle date ............................................................... 222
7.5.6 Funzioni di conversione ....................................................... 229
7.5.7 Formati per la rappresentazione delle date ......................... 232
7.5.8 Formati per la rappresentazione dei numeri ........................ 235
7.5.9 Gestione dei valori nulli ........................................................ 236
7.5.10 Espressioni regolari ............................................................. 241
7.5.11 DECODE e CASE ................................................................ 245
7.5.12 GREATEST e LEAST .......................................................... 249
7.6 JOIN: ricerche da pi tabelle ....................................................... 250
7.6.1 Sintassi per la JOIN ............................................................. 250
7.6.2 Prodotto cartesiano di tabelle .............................................. 251
7.6.3 Inner join .............................................................................. 253
7.6.4 Outer join ............................................................................. 255
7.6.5 Le clausole APPLY e LATERAL .......................................... 264
7.7 Gli operatori insiemistici ............................................................... 267
7.7.1 UNION ................................................................................. 267
7.7.2 UNION ALL .......................................................................... 270
7.7.3 INTERSECT ......................................................................... 271
7.7.4 MINUS ................................................................................. 271
7.8 Ricerche innestate ....................................................................... 272
7.8.1 Operatori di confronto .......................................................... 273
7.8.2 Subquery correlate e scorrelate ........................................... 277
5
7.8.3 La clausola WITH................................................................. 279
7.9 Comandi TCL ............................................................................... 280
7.9.1 Gestione delle transazioni.................................................... 280
7.9.2 COMMIT............................................................................... 280
7.9.3 ROLLBACK .......................................................................... 282
7.9.4 SAVEPOINT......................................................................... 283
7.9.5 SET TRANSACTION ........................................................... 285
7.9.6 Lock di dati ed oggetti .......................................................... 289
7.9.7 Una situazione particolare, il deadlock ................................ 290
7.10 Comandi DCL .............................................................................. 291
7.10.1 GRANT................................................................................. 291
7.10.2 REVOKE .............................................................................. 292
7.10.3 RUOLI .................................................................................. 293
8 PL/SQL ................................................................................................ 294
8.1 Blocchi PL/SQL anonimi .............................................................. 294
8.2 Struttura di un blocco PL/SQL anonimo ...................................... 295
8.3 Dichiarazione di costanti e variabili .............................................. 297
8.3.1 Tipi di dato............................................................................ 297
8.3.2 Dichiarazione di variabili ...................................................... 298
8.3.3 Dichiarazione di costanti ...................................................... 299
8.4 Costrutti di base ........................................................................... 299
8.4.1 Assegnazione di un valore. .................................................. 299
8.4.2 Strutture Condizionali ........................................................... 299
8.4.3 Strutture Iterative ................................................................. 302
8.4.4 Strutture Sequenziali ............................................................ 305
8.5 Utilizzo dellSQL ........................................................................... 307
8.5.1 SQL Statico .......................................................................... 307
8.5.2 SQL Dinamico ...................................................................... 308
8.5.3 CURSORI............................................................................. 312
8.6 Gestione delle eccezioni .............................................................. 315
8.6.1 Blocco Exception ................................................................. 315
8.6.2 Eccezioni predefinite ............................................................ 316
8.6.3 SQLCODE e SQLERRM ...................................................... 320
8.6.4 Sollevare uneccezione ........................................................ 321
8.6.5 Eccezioni utente ................................................................... 322
8.6.6 Eccezioni mute ..................................................................... 323
8.6.7 Eccezioni in un ciclo ............................................................. 323
8.6.8 Propagazione delle eccezioni .............................................. 325
8.7 Tipi di dato complessi .................................................................. 326
8.7.1 Record.................................................................................. 326
8.7.2 Array associativi (PL/SQL Tables) ....................................... 329
8.7.3 Varray................................................................................... 333
8.7.4 Nested Table ........................................................................ 335
8.7.5 Bulk collect ........................................................................... 336
8.7.6 Metodi delle collezioni .......................................................... 337
8.8 Oggetti PL/SQL nel DB ................................................................ 344
8.8.1 Procedure............................................................................. 344
8.8.2 Funzioni................................................................................ 352
8.8.3 Package ............................................................................... 357
6
8.8.4 Database Trigger ................................................................. 365
8.8.5 Dipendenze tra oggetti del DB ............................................. 378
8.8.1 La clausola ACCESSIBLE BY ............................................. 381
8.8.2 Diritti desecuzione ............................................................... 382
8.8.3 La clausola BEQUEATH delle viste ..................................... 385
8.8.4 Controllo del codice PL/SQL ................................................ 387
8.8.5 Le direttive di compilazione PRAGMA ................................. 390
9 Cloud e Multitenant Architecture ......................................................... 398
9.1 C come Cloud .............................................................................. 398
9.2 Introduzione alla Multitenant Architecture ................................... 399
9.3 Containers in un CDB .................................................................. 400
9.3.1 Il container CDB$ROOT ...................................................... 400
9.3.2 I container PDB .................................................................... 400
9.3.3 Container corrente ............................................................... 401
9.3.4 Data Dictionary in un CDB ................................................... 401
9.4 Utenti e ruoli in un CDB ............................................................... 402
9.4.1 Utenti comuni o locali ........................................................... 402
9.4.2 Ruoli comuni o locali ............................................................ 403
9.5 Architettura fisica di un CDB ........................................................ 404
9.6 Operazioni amministrative in un CDB .......................................... 404
9.6.1 Avviare ed arrestare Oracle ................................................. 404
9.6.2 Connettersi al database ....................................................... 405
9.6.3 Unplug e trasferimento di un PDB ....................................... 406
9.6.4 Duplicazione di un PDB ....................................................... 407
9.6.5 PDB Trigger ......................................................................... 409
10 Prerequisiti .......................................................................................... 413
10.1 Database e database relazionali ................................................. 413
10.1.1 database .............................................................................. 413
10.1.2 database relazionali ............................................................. 414
10.1.3 DBA ...................................................................................... 415
10.2 Progettazione di un db relazionale .............................................. 415
10.2.1 Modello entit/relazioni ........................................................ 415
10.2.2 Normalizzazione .................................................................. 416
10.2.3 Definizione dello schema fisico ............................................ 419
10.3 Architettura di un computer .......................................................... 419
10.3.1 Architettura Hardware .......................................................... 420
10.3.2 Architettura Software ........................................................... 420
10.4 Memorizzazione dei dati .............................................................. 421
10.4.1 I sistemi binario ed esadecimale.......................................... 421
10.4.2 Dal bit al TeraByte ............................................................... 422
10.4.3 La tabella ASCII ................................................................... 423
10.5 Rappresentazioni numeriche ....................................................... 423
10.5.1 Virgola fissa ......................................................................... 423
10.5.2 Virgola mobile ...................................................................... 424
10.6 Algoritmi di ricerca ....................................................................... 424
10.6.1 Ricerca sequenziale............................................................. 424
10.6.2 Ricerca dicotomica (o binaria) ............................................. 424
10.7 Algoritmi e funzioni di HASH........................................................ 425
10.8 Teoria degli insiemi ...................................................................... 425
7
10.8.1 Insiemi e sottoinsiemi........................................................... 425
10.8.2 Intersezione di insiemi ......................................................... 426
10.8.3 Unione di insiemi .................................................................. 426
10.8.4 Complemento di insiemi....................................................... 426
10.8.5 Prodotto cartesiano di insiemi .............................................. 426
10.9 Logica delle proposizioni.............................................................. 426
10.9.1 Operatore di congiunzione ................................................... 427
10.9.2 Operatore di disgiunzione .................................................... 427
10.9.3 Operatore di negazione ....................................................... 427
10.9.4 Regole di precedenza .......................................................... 427
10.9.5 Leggi di De Morgan .............................................................. 428
10.10 Logica delle proposizioni e teoria degli insiemi........................ 428
Indice Analitico ............................................................................................. 430
Indice delle figure ......................................................................................... 437
8
Introduzione
10
1 Architettura di Oracle
11
1.2.1 PMON Process Monitor
Si occupa di monitorare gli altri processi e riavviarli nel caso in cui
terminino in maniera inattesa.
12
Database Buffer Cache: include tutti i blocchi contenenti dati prelevati
dal database (quindi dal disco fisso) e messi in RAM per essere letti e/o
modificati.
Redo Log Buffer: contiene le informazioni che saranno scritte dal
LGWR sui Redo Log Files.
Shared Pool: contiene informazioni di sistema (parametri, istruzioni SQL
o PL/SQL gi parzialmente elaborate, contenuto del dizionario dati) che
sono state gi utilizzate e potrebbero essere di nuovo utili per successive
elaborazioni.
Large Pool: unarea di memoria opzionale destinata a contenere ci
che troppo grande per essere contenuto nella Shared Pool.
Java Pool: unarea dedicata a contenere i programmi java che
vengono eseguiti nellambito del DB
importante sottolineare che la SGA, essendo condivisa, utilizzata
da tutti i processi che accedono al DB. Per fare un esempio, ipotizziamo che,
mediante unapplicazione web, un utente visualizzi i dati del cliente 111111.
Oracle accede al disco fisso dove sono conservati i dati del cliente e li porta
in memoria RAM, mettendoli nella Database Buffer Cache. Successivamente
i dati vengono restituiti alla pagina web e visualizzati. Se un secondo utente
si collega al DB, anche in unaltra modalit, ad esempio utilizzando il tool
Oracle Sql*Plus (vedi capitolo 4), e cerca i dati del cliente 111111 Oracle
potr rispondere leggendo direttamente la SGA, senza dover di nuovo
accedere al file contenente i dati che si trova sul disco fisso. Ci consente un
grande miglioramento dei tempi di risposta perch un accesso al disco fisso
enormemente pi lento di un accesso alla memoria RAM.
13
una testata, in cui Oracle conserva informazioni sul blocco e sui dati che
esso contiene,
uno spazio libero da utilizzare nel caso in cui i dati contenuti nel blocco
vengano modificati in momenti successivi allinserimento,
i dati di una serie di righe appartenenti ad una stessa tabella,
spazio vuoto da utilizzare per ulteriori righe della stessa tabella.
I blocchi non vengono riempiti mai per intero. Ogni volta che un utente
inserisce una riga in una tabella, Oracle aggiunge una nuova riga nel blocco
corrente facendo sempre attenzione a lasciare libero lo spazio riservato per
gli aggiornamenti dei dati. Se Oracle determina che linserimento della nuova
riga nel blocco farebbe diminuire eccessivamente lo spazio libero, passa al
blocco successivo ed inserisce l la nuova riga. La dimensione dello spazio
libero minimo per ogni blocco pu essere definita in fase di creazione del
database o delle singole tabelle.
1.4.2 Extent
Vista lesigua dimensione di un blocco, questo potr contenere poche
righe di una tabella. Quante righe possono essere contenute in un blocco
dipende dal numero di dati presenti in tabella e da quanto spazio questi
occupano. In ogni caso sarebbe inefficiente per Oracle dover riservare un
blocco alla volta ogni volta che il blocco corrente saturo. Per semplificare le
cose Oracle riserva alla tabella un certo numero di blocchi consecutivi
presenti nel datafile. Un insieme di blocchi consecutivi che vengono prenotati
da Oracle tutti per la stessa tabella prendono il nome di extent. Dunque
possiamo dire che la parte gi utilizzata di un datafile logicamente
suddivisa in tanti extent. Ogni extent un insieme di blocchi consecutivi tutti
dedicati a contenere i dati della stessa tabella. Quando Oracle non ha pi
spazio per inserire nellultimo blocco disponibile nellextent corrente prenota
un nuovo extent. Quanti blocchi compongono lextent? Dipende. Si pu fare
in modo che sia Oracle a gestire in autonomia questo aspetto oppure
lasciare al DBA la gestione degli extent. La scelta di default, fortemente
consigliata da Oracle, la prima.
1.4.3 Tablespace
Oracle mette a disposizione dei contenitori logici per le tabelle che
possono essere costituiti da uno o pi datafile. Questi contenitori prendono il
nome di tablespace. In pratica quando si crea una tabella bisogna che Oracle
sappia in quale tablespace deve andare a mettere i dati, sceglier poi
autonomamente quale dei file del tablespace utilizzare. I dati di una tabella
stanno sempre tutti sullo stesso tablespace, ma possono essere scritti in
datafile diversi. Il tablespace che si intende utilizzare pu essere
esplicitamente indicato in fase di creazione della tabella, oppure Oracle
utilizzer un tablespace di default.
14
1.4.4 Segment
Fin qui abbiamo descritto le modalit di memorizzazione dei dati delle
tabelle. In un database, per, ci possono essere anche altri tipi di oggetto. Il
capitolo 5 dedicato ad una carrellata sui diversi oggetti che si possono
trovare in un database Oracle, alcuni di questi contengono dati e dunque
occupano spazio come le tabelle, altri no. Gli oggetti del primo tipo vengono
detti segment. Tutto ci che abbiamo detto nel paragrafo 1.4 si adatta a tutti i
segment, di cui le tabelle sono un caso particolare.
16
2 Installazione
17
Figura 2-1 Multitenant Architecture: scelta tra CDB o non-CDB
Tutti gli esempi che seguono sono relativi ad unarchitettura Oracle
classica (versioni di Oracle fino alla 11g oppure un non-CDB in Oracle 12c),
ad eccezione degli esempi mostrati nel capitolo 9, che assumono di avere a
disposizione un CDB in Oracle 12c.
18
3 Operazioni preliminari
sqlplus / as sysdba
19
Ovviamente perch questo comando abbia successo necessario che
lutente di sistema operativo abbia i privilegi adatti. Utilizzando la stessa
utenza che si utilizzata per installare il DB di sicuro non si sbaglia.
3.1.1 Startup
La procedura di startup consiste nellavviare un database spento e si
concretizza nel susseguirsi dei seguenti quattro stati:
SHUTDOWN, listanza ferma ed il database non disponibile
NOMOUNT, listanza attiva ed il database non disponibile
MOUNT, listanza attiva ed il db disponibile solo per operazioni di
amministrazione
OPEN, listanza attiva ed il database disponibile per tutte le
operazioni.
Il comando che consente di passare dallo stato SHUTDOWN
direttamente ad uno degli altri tre stati STARTUP, specificando la parola
chiave NOMOUNT o MOUNT se si desidera andare in uno di questi due stati
intermedi. Il comando STARTUP da solo porta direttamente allo stato OPEN.
Il comando che invece consente di passare dallo stato NOMOUNT a
MOUNT, da MOUNT ad OPEN o direttamente da NOMOUNT ad OPEN
ALTER DATABASE seguito dallo stato desiderato. Ad esempio ALTER
DATABASE OPEN porta il DB in stato OPEN sia partendo dallo stato
NOMOUNT che partendo dallo stato MOUNT.
3.1.2 Shutdown
Il processo di shutdown esegue gli step inversi di quello di startup. Il
comando SQL*Plus da utilizzare SHUTDOWN che rende indisponibile il db
ed arresta listanza a partire da qualunque stato.
Esistono quattro diverse modalit di SHUTDOWN:
SHUTDOWN NORMAL, la modalit di default ed equivale al semplice
SHUTDOWN. Il database non viene spento immediatamente, non
vengono accettate nuove connessioni ma il db resta in piedi fino a
quando tutti gli utenti gi collegati si siano volontariamente disconnessi.
Lo shutdown effettivo pu quindi avvenire anche molto tempo dopo
lesecuzione del comando.
SHUTDOWN TRANSACTIONAL, Il database non viene spento
immediatamente, non vengono accettate nuove connessioni ma il db
resta in piedi fino a quando tutti gli utenti gi collegati decidano
volontariamente di salvare o annullare le modifiche apportate ai dati. Una
volta che un utente salva o annulla le sue modifiche viene disconnesso
automaticamente e non pu pi riconnettersi. Come prima, lo shutdown
pu avvenire anche molto tempo dopo lesecuzione del comando.
SHUTDOWN IMMEDIATE , Oracle esegue un checkpoint e butta fuori
tutti gli utenti collegati. Le modifiche degli utenti non salvate andranno
perse.
20
SHUTDOWN ABORT , Equivale a staccare la spina del server su cui
Oracle installato, non c tempo per fare nulla, alla ripartenza di Oracle
sar sicuramente eseguito un recovery.
Un esempio di shutdown e startup del database da Sql*Plus
presentato in Figura 3-1.
21
concettualmente sono due cose diverse, ai fini pratici sono sostanzialmente
la stessa cosa.
Quando si installa Oracle vengono creati automaticamente vari utenti
di sistema con i relativi schemi. Due di questi ci interessano particolarmente:
SYS e SYSTEM. Le password di questi due utenti sono state scelte in fase di
installazione.
Lutente SYS il superutente, proprietario di tutti gli oggetti di sistema,
dovrebbe essere utilizzato solo per particolarissime operazioni di
amministrazione.
Lutente SYSTEM comunque un utente speciale, ha ampia delega
da parte di SYS ad eseguire la maggior parte delle attivit di amministrazione
e dovrebbe essere utilizzato solo per queste. Una delle operazione che
tipicamente vengono fatte utilizzando SYSTEM la creazione di altri
utenti/schemi.
22
server, quindi prima di tutto ci deve essere una rete tra client e server. Di
norma client e server utilizzano come protocollo di comunicazione il TCP/IP e
il client deve conoscere il nome del server oppure il suo indirizzo IP. Una
volta che il client ha note queste due informazioni pu aprire una
connessione verso il server. A questo punto necessario capire cosa
succede sul server. Per poter accettare connessioni dallesterno un server
deve avere attivo un programma che sia in grado di ricevere le connessioni
TCP/IP e smistarle verso Oracle. Questo programma si chiama listener.
Siccome sul server ci potrebbero essere pi programmi in attesa di
connessioni TCP/IP, programmi che servono ad Oracle oppure ad altro,
necessario che il listener sia in ascolto su una porta particolare e che il client
quando si connette conosca questa porta. Per default la porta su cui i listener
Oracle si mettono in ascolto la 1521, ma questo parametro pu essere
modificato a piacere dallamministratore del database.
Se avete installato Oracle su Windows stato creato un servizio che
consente di avviare ed arrestare il listener.
In qualunque sistema operativo il listener si controlla con il tool lsnrctl
che pu essere utilizzato da prompt dei comandi.
Per avviare il listener useremo il comando
lsnrctl start
lsnrctl stop
23
Torniamo ai parametri di connessione. Alcuni programmi client di
fornitori terzi che si collegano ad Oracle vi chiederanno esplicitamente di
indicare i quattro parametri. Tutti i programmi client forniti da Oracle e molti
anche di terze parti, invece, richiedono che sul client venga fatta una
speciale configurazione. In pratica in un file di sistema che si trova sul client
bisogna indicare, per ogni database Oracle a cui ci si intende collegare, un
nome mnemonico per questa connessione associato ai quattro parametri di
cui abbiamo parlato. Il nome mnemonico detto connect string, quando ci si
collega ad Oracle, dunque, sar sufficiente fornire utente, password e
connect string. Il programma utilizzato per collegarsi sar in grado di ricavare
dalla connect string i quattro parametri di base ed effettuare la connessione.
Il file di configurazione in cui si definiscono le connect string si chiama
tnsnames.ora e si trova nella cartella Admin sotto la directory Network nella
Oracle Home in cui stato installato il client Oracle.
Il tnsnames.ora non andrebbe mai modificato manualmente, anche se
prassi comune farlo. Per modificare il tnsnames.ora Oracle mette a
disposizione un programma che si chiama Net Manager e si trova nel men
avvio.
Ovviamente il men pu cambiare per versioni diverse di Oracle,
infatti in generale possibile collegarsi ad un server Oracle di una certa
versione con un client di versione differente. Vediamo passo per passo la
configurazione di una nuova connect string da Net Manager.
24
Figura 3-2 La maschera principale di Net Manager
25
Passo 2 Inserire la nuova connect string che si intende creare e fare clic su
Avanti
26
Passo 4 Indicare il nome (oppure lindirizzo IP) del server e la porta su cui
il listener in ascolto e fare clic su Avanti.
27
Passo 6 Cliccare su Test per effettuare il test della connessione
28
Passo 8 Indicare le credenziali corrette (in questo esempio esiste un
utente che si chiama corso, si pu anche usare SYSTEM o un qualunque
altro utente) e fare clic su OK e poi su Test
29
Passo 10 Chiudere Net Manager e salvare le modifiche
miodb =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = servername)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = CORSO)
)
)
sqlplus corso/corsopwd@miodb
sqlplus
30
Figura 3-12 Connessione con Sql*Plus da client remoto.
31
4 SQL*Plus e SQL Developer
4.1 SQL*Plus
SQL*Plus un tool a linea di comando (non grafico) presente in
Oracle fin dalla versione 5. stato per anni lunico strumento fornito con il
DB sia per lamministrazione che per la gestione dei dati. Dalla versione 7
alla versione 10g Release 2 del database, e solo in ambiente Windows,
Oracle ha fornito anche una versione graficamente pi evoluta di SQL*Plus
che stata eliminata nella versione 11g. Da questa scelta traspare
lorientamento di Oracle a continuare il supporto di SQL*Plus solo al fine di
consentire agli utenti la realizzazione di alcune attivit molto specifiche, in
particolare quelle che richiedono una forte automatizzazione, e spingere il
grosso degli utenti allutilizzo del nuovo strumento grafico, SQL Developer,
fornito a partire dalla Release 2 di Oracle 10g.
32
4.1.1 Perch ancora SQL*Plus
Nonostante questa tendenza alla riduzione dellambito di SQL*Plus sia
ormai evidente, mia opinione che un corso base sul database Oracle non
possa prescindere dallutilizzo di questo strumento. Se vero, infatti, che
SQL Developer ha copertura funzionale maggiore di SQL*Plus, anche vero
che esistono in giro molte installazioni di Oracle ferme alla versione 9i, se
non addirittura alla 8 o 8i. Su tali installazioni non c nessuna valida
alternativa allutilizzo di SQL*Plus (a meno che, ovviamente, non si intenda di
utilizzare prodotti di terze parti).
Dal punto di vista strettamente didattico, poi, lutilizzo dello strumento a
linea di comando obbliga lo studente ad affrontare le difficolt dovute alla
sintassi dei comandi, laddove lo strumento grafico molto spesso agevola
lutilizzatore con utility e wizard che eliminano tali difficolt. In fase di
apprendimento la necessit di dover scrivere, e spesso riscrivere pi volte,
unistruzione nella sintassi corretta aiuta a comprendere a fondo il senso di
ci che si sta facendo; la disponibilit di utility troppo semplici, invece, tende
a far trascurare i dettagli. Lo studente che impara a creare una tabella
usando il comando CREATE TABLE, di sicuro non avr difficolt in futuro a
portare a termine la stessa attivit utilizzando un qualunque strumento
grafico. Il viceversa ovviamente non vale.
33
Figura 4-2 Propriet di SQL*Plus.
Si pu poi passare ad impostare a piacimento il tipo di carattere ed i
colori. Quello che assolutamente conviene fare aumentare la dimensione
delle righe e delle colonne visualizzate, cliccando su Layout basta
impostare i campi come in Figura 4-3.
35
SQL*Plus leggere o scrivere file che si trovano in cartelle differenti, sar solo
necessario indicare esplicitamente il path oltre al nome dei file.
Ad esempio
Show linesize
mostra il valore del parametro linesize, per default 80, che rappresenta
il numero di caratteri che formano ogni linea orizzontale in SQL*Plus.
Siccome abbiamo allargato la finestra per contenere 157 caratteri in
orizzontale (Figura 4-3) non ha senso tenere la linesize ad 80 caratteri, i
restanti 77 resterebbero sempre inutilizzati. Impostiamo dunque la larghezza
della linea di SQL*Plus a 156 caratteri (per una visualizzazione ottimale
36
conviene tenere la linea di SQL*Plus un carattere pi piccola della linea
visualizzabile nella finestra):
set linesize 156
che mostra la struttura della tabella DICT. Questa tabella (in verit non
si tratta proprio di una tabella ma di una vista, al momento non fa alcuna
differenza), contiene lindice del dizionario dati. Il dizionario dati un
insieme di tabelle che contengono informazioni su tutti gli oggetti presenti nel
database. Loutput del comando DESC, come evidenziato in Figura 4-8,
mostra un riepilogo delle colonne della tabella DICT. Per ogni colonna viene
visualizzato il nome, se sempre valorizzata oppure no ed il tipo di dati
contenuti nella colonna. Non ci soffermiamo adesso su queste informazioni
perch saranno ampiamente trattate nel capitolo dedicato al linguaggio SQL.
37
Figura 4-8 Il comando DESC.
Non esamineremo in questo capitolo uno per uno i parametri ed i
comandi di SQL*Plus perch da un lato non trarremmo alcun beneficio
immediato da una noiosa carrellata di comandi ed opzioni e, dallaltro, non
avendo ancora introdotto lSQL, sarebbe difficoltoso fare esempi significativi.
I parametri ed i comandi che servono saranno illustrati nei prossimi capitoli,
laddove ci sar bisogno di utilizzarli.
39
Figura 4-11 Apertura di afiedit.buf
oppure
@c:\test.sql
42
4.2 SQL Developer
SQL Developer un tool grafico scritto in Java che, nelle intenzioni di
Oracle, dovrebbe raccogliere leredit di SQL*Plus fornendo uninterfaccia
utente pi accattivante ed intuitiva.
44
Figura 4-18 Esecuzione di unistruzione SQL.
45
5 Oggetti del DB
46
WTO> desc dictionary
Nome Nullo? Tipo
--------------------------------------- -------- -------------
TABLE_NAME VARCHAR2(30)
COMMENTS VARCHAR2(4000)
47
Figura 5-1 Lettura del dizionario da SQL*Plus.
In alternativa si pu utilizzare SQL Developer (Figura 5-2).
48
Tabelle il cui nome inizia per USER_ contengono informazioni su
tutti gli oggetti di propriet dellutente che esegue la query.
Tabelle il cui nome inizia per ALL_ contengono informazioni su
tutti gli oggetti a cui lutente che esegue la query ha diritto di accedere.
Un utente ha sicuramente diritto di accedere agli oggetti di sua propriet,
ma anche agli oggetti di propriet di altri utenti per cui stato autorizzato
mediante il comando SQL GRANT.
Tabelle il cui nome inizia per DBA_ contengono informazioni su
tutti gli oggetti contenuti nel database, queste tabelle sono accessibili
solo agli utenti speciali che hanno privilegi tali da essere considerati
amministratori di database.
Tabelle il cui nome inizia per V$ e GV$ Si tratta delle cosiddette
viste dinamiche. Il contenuto di queste tabelle cambia continuamente in
funzione dello stato del database e non soltanto degli oggetti che
vengono creati e distrutti. Da queste tabelle si pu, per esempio, sapere
in un determinato istante quanti utenti sono collegati al database e cosa
stanno facendo oppure quanta memoria in uso. Anche queste tabelle
sono utilizzabili solo dagli utenti che hanno privilegi di amministratore.
Tabelle il cui nome inizia per CDB_ presenti a partire da Oracle
12c, contengono informazioni su tutti gli oggetti contenuti nel database
contenitore ed in tutti i pluggrable Db in esso contenuti.
Le tabelle degli ultimi tre gruppi contengono informazioni essenziali per
lamministrazione del database, quindi vanno oltre gli obiettivi introduttivi di
questo corso. Le tabelle ALL sono praticamente identiche alle USER a meno
del fatto che nelle ALL c in pi la colonna OWNER che indica chi il
proprietario delloggetto (nella USER non ce n bisogno perch il
proprietario per definizione chi sta eseguendo la query). Per questi motivi
nel seguito saranno menzionate sempre le tabelle USER.
5.2 Tabelle
Sono le protagoniste indiscusse del database. I concetti che sono alla
base delle tabelle relazionali sono stati gi descritti nel paragrafo 10.1.3.
Come visto possibile visualizzarne la struttura utilizzando il comando DESC
di SQL*Plus oppure navigando nellelenco di sinistra di SQL Developer,
come in Figura 5-3.
WTO> DESC PROVA
Nome Nullo? Tipo
----------------------------- -------- ----------------
A NUMBER
B NOT NULL VARCHAR2(20)
C DATE
49
Figura 5-3 Caratteristiche principali di una tabella.
Le tecniche utilizzate da Oracle per la memorizzazione dei dati di una
tabella sono stati gi discusse, si pu aggiungere che in casi del tutto
particolari i dati di una tabella possono risiedere al di fuori del database
(External Table) oppure essere suddivisi in sottotabelle (Partizioni) per
velocizzare laccesso ai dati. Questi tipi particolari di tabelle si comportano,
dal punto di vista dellutente, in maniera del tutto analogo alle tabelle
standard.
50
5.2.2 Constraint
Un constraint una regola che devono verificare i dati per poter
essere contenuti in tabella. Il primo tipo di constraint definito implicitamente
che stato gi incontrato la conformit al tipo di dato. Quando, in fase di
creazione o di modifica della tabella, si indica che una colonna di tipo
numerico si sta implicitamente richiedendo ad Oracle di controllare i dati che
saranno inseriti e rigettare tutto ci che non numerico.
Anche lobbligatoriet di una colonna un constraint. Definire una
colonna NOT NULL equivale a definire un vincolo che Oracle dovr
verificare ogni qual volta i dati saranno inseriti o modificati.
Altri constraint che possono essere definiti sono quelli che vincolano
Oracle ad attenersi ai principi di integrit referenziale come definiti al
paragrafo 10.1.2:
Primary Key Chiave primaria. un constraint che consente allutente
di definire che una colonna, oppure un insieme di colonne, funge da
chiave primaria della tabella. Conseguenza dellesistenza di questo
constraint sar che
1. La colonna o le colonne inserite in chiave primaria diventano
obbligatorie.
2. Non sar mai possibile inserire due righe in tabella aventi lo stesso
valore, oppure la stessa combinazione di valori, nella chiave
primaria.
Foreign Key Chiave esterna. un constraint che consente allutente
di definire che una colonna, oppure un insieme di colonne, un
riferimento alla chiave primaria di unaltra tabella. La tabella su cui
definita la chiave esterna si dice tabella figlia mentre la tabella su cui si
trova la chiave primaria referenziata si dice tabella madre.
Conseguenza dellesistenza di questo constraint sar che:
1. La colonna o le colonne inserite in chiave esterna nella tabella figlia
possono assumere solo valori gi contenuti nella chiave primaria
della tabella madre.
2. Non sar mai possibile cancellare una riga dalla tabella madre se ci
sono righe nella tabella figlia che contengono quei valori.
Per maggiore chiarezza si faccia riferimento agli esempi del paragrafo
10.1.2.
In alcuni casi oltre alla primary key della tabella pu succedere che
altre colonne, o combinazioni di colonne, non debbano poter assumere gli
stessi valori in righe differenti. Si pensi come esempio al codice fiscale nelle
tabelle di anagrafe dei clienti. Il codice fiscale non pu quasi mai essere
utilizzato come chiave primaria perch spesso non viene fornito o viene
fornito in un secondo momento dai clienti e dunque raramente si pu
considerare un campo obbligatorio. Quando viene fornito, per,
51
normalmente un dato univoco. Non ci possono essere due clienti in anagrafe
che hanno lo stesso codice fiscale, altrimenti c un errore oppure si tratta
della stessa persona. Per queste situazioni esiste il constraint unique key,
chiave univoca.
Un altro tipo di vincolo molto utilizzato il check constraint che
consente di fissare una regola che i dati di una riga devono verificare in fase
di inserimento o aggiornamento. Ad esempio si pu verificare che un numero
o una data siano compresi in un dato intervallo oppure che una colonna
assuma solo i valori S oppure N. Il controllo pu coinvolgere anche pi
colonne della stessa riga, ad esempio se si sta definendo la tabella dei
prestiti di una biblioteca si pu imporre che la data restituzione sia maggiore
o uguale della data del prestito.
Tutti i constraint possono essere temporaneamente disabilitati. La loro
definizione, in questo caso, resta associata alla tabella ma essi non vengono
pi controllati. Alla riabilitazione del constraint Oracle ricontrolla i dati per
verificare se questi violano il constraint da abilitare, in tal caso viene sollevato
un errore.
5.3 Indici
Uno dei maggiori problemi nellutilizzo dei database lottimizzazione
dei tempi di risposta delle ricerche. Frequentemente le tabelle contengono
milioni di righe e spesso vengono lette insieme a molte altre tabelle in
istruzioni SQL molto complesse.
Lottimizzazione di un database Oracle unattivit di elevata
complessit che richiede competenze di tipo amministrativo e sicuramente gli
si potrebbe dedicare un manuale a se stante. In questo corso il tema sar
approcciato solo da un particolare punto di vista, quello dellutente di
database che scrive una query. Volendosi concentrare solo sullaspetto
utente dellottimizzazione il tema fondamentale da trattare sicuramente
quello degli indici: strutture di dati che consentono lindividuazione veloce di
un valore specifico in una colonna di database.
Si ipotizzi dunque di avere la solita tabella CLIENTI contenente il
codice del cliente, il cognome, il nome e tutti gli altri dati anagrafici. Si ipotizzi
poi che la tabella contenga un milione di righe.
I record della tabella non sono registrati nel database in nessun ordine
specifico, se eseguiamo quindi la ricerca dei clienti il cui cognome ROSSI
Oracle sar costretto a scorrere un milione di righe, scartare tutti i clienti che
non si chiamano Rossi e prendere gli altri. Sarebbe tutto molto pi semplice
se i record fossero ordinari per cognome, in quel caso infatti mediante una
ricerca dicotomica ( 10.6) sarebbe possibile trovare i Rossi in, al pi, 21
letture. Oracle per non pu certo archiviare i dati sul disco in uno specifico
ordine, quindi necessario utilizzare delle strutture dati aggiuntive che
consentano di velocizzare laccesso.
52
5.3.1 Indici B-Tree
Definire un indice sulla colonna Cognome della tabella CLIENTI
significa chiedere ad Oracle di creare, e tenere sempre aggiornata, una
nuova struttura dati in cui siano presenti in una struttura ad albero tutti i
cognomi della tabella CLIENTI, ad ogni cognome sar associato un codice
(rowid) che indica la collocazione fisica (file, blocco, riga) del record che
contiene quel valore. Lalbero composto da un certo numero di livelli, al
primo livello c un solo gruppo che fa da indice tra i gruppi di secondo livello,
cos procedendo ad ogni livello ogni gruppo gestisce un gruppo sempre pi
piccolo di cognomi e fa da indice per il gruppo di livello inferiore. Allultimo
livello, nelle foglie dellalbero, ci sono i singoli cognomi ognuno associato al
suo rowid. Per un esempio si faccia riferimento alla Figura 5-4. Dovendo
cercare un cognome particolare Oracle partir dal primo nodo in altro e
percorrer lalbero un livello alla volta fino ad arrivare alla foglia che contiene
il cognome cercato. A quel punto utilizzer il rowid per recuperare il record
legato a quel cognome.
Da A- a M
Da N- a Z
Da A- a F Da N- a S
Da G- a M Da T- a Z
53
Il B-Tree il tipo di indice predefinito in Oracle ma genera dei notevoli
problemi quando una colonna indicizzata assume pochi valori distinti.
Ipotizzando di indicizzare il campo SESSO, che assume solo due possibili
valori, la ricerca di tutti i clienti cha hanno SESSO=M sar pi lenta di una
ricerca sequenziale. Ipotizzando infatti che la met dei clienti sia maschio
laccesso allindice restituir cinquecentomila rowid e per ognuno di esso
sar fatto un accesso al datafile per recuperarne i dati. In questo scenario la
presenza dellindice B-Tree non solo non agevola, ma addirittura peggiora
drasticamente i tempi di esecuzione della ricerca.
Tabella creata.
Indice creato.
54
Non possibile perch il primo visibile, allora procediamo rendendo
prima invisibile il primo indice:
O12c>alter index test1 invisible;
Modificato indice.
Indice creato.
Modificato indice.
Indice creato.
5.4 IOT
Una tabella index-organized ha tutte le caratteristiche di una tabella
classica a parte il fatto che, internamente, i dati sono archiviati in una
struttura B-Tree basata sulla primary key.
Ovviamente, mentre una tabella classica pu essere priva di primary
key, una IOT ne deve essere necessariamente fornita.
Dal punto di vista dellutente non c alcuna differenza tra una tabella
di questo tipo ed una classica.
55
Conviene utilizzate una IOT quando la maggior parte delle ricerche
sulla tabella includono tra i criteri di ricerca una condizione sulla primary key.
Una index-organized table , ovviamente, un segment.
5.6 Viste
Una tabella , come visto, un contenitore di dati generalmente relativi
ad una specifica entit del sistema. Ad esempio si potrebbe definire la tabella
dei clienti, quella degli ordini oppure quella delle fatture. Normalmente
accade di dover accedere ai dati di pi tabelle contemporaneamente, voler
quindi vedere contemporaneamente i dati di clienti, ordini e fatture. Ci pu
essere effettuato mediante una query su pi tabelle, si tratta di una istruzione
SQL complessa del tipo descritto nel paragrafo 7.5.11 e successivi. Una vista
non altro che un nome assegnato ad una tale query SQL complessa. Una
56
vista dunque non contiene dati, ma solo la definizione di una istruzione SQL.
Lutente per interagisce con la vista come se fosse una qualunque tabella,
pu vederne la struttura utilizzando il comando DESC e leggerne tutti i dati
con il comando
SELECT * FROM <NOME_VISTA>
57
essere piuttosto lenta. Oltre ad applicare tutti i metodi di ottimizzazione del
database o delle singole istruzioni SQL, come la creazione di indici, in queste
occasioni si pu ricorrere alle viste materializzate, in inglese materialized
views.
Tali oggetti vengono definiti in maniera simile alle viste ma, allatto
della creazione, vengono effettivamente riempite con i dati estratti dalla query
SQL. Ovviamente questi dati duplicati diventano obsoleti non appena
cambiano i dati contenuti in una delle tabelle su cui la vista insiste. Per tale
motivo necessario aggiornare la vista materializzata manualmente prima di
utilizzarla oppure impostare laggiornamento automatico periodico.
Laggiornamento pu essere completo o rapido (fast in inglese).
Laggiornamento completo cancella tutti i record dalla vista e reinserisce il
risultato della query completa. Per eseguire laggiornamento rapido, Oracle
tiene traccia in una tabella di log delle modifiche intervenute sulle tabelle
originali dallultimo aggiornamento e, al momento del nuovo aggiornamento,
riporta solo i cambiamenti effettivi.
Se in fase di definizione della vista non si definita una politica di
aggiornamento automatico periodico, si pu eseguire un aggiornamento
manuale utilizzando la procedura REFRESH del package di sistema
DBMS_MVIEW.
Le viste materializzate occupano un proprio spazio, quindi sono dei
segment.
5.8 Sequenze
Le sequenze sono generatori di numeri progressivi univoci. Sono
spesso utilizzate per valorizzare la chiave primaria di una tabella.
Una sequenza pu partire dal numero uno oppure da un altro numero
a scelta, incrementarsi o decrementarsi di una o pi unit ad ogni utilizzo,
avere un valore massimo predefinito oppure no, riprendere dal numero
iniziale quando si esaurisce oppure no.
La sequenza non un segment.
5.9 Sinonimi
Un sinonimo un nome alternativo che viene assegnato ad un oggetto
del database. Abbiamo gi incontrato alcuni sinonimi, DICT sinonimo di
SYS.DICTIONARY, CAT sinonimo di SYS.USER_CATALOG.
Non c un limite al numero di sinonimi che possono essere assegnati
ad un oggetto. Il sinonimo pu essere privato, cio utilizzabile solo dallutente
che lo definisce, oppure pubblico cio utilizzabile da tutti gli utenti del
database. DICT e CAT sono sinonimi pubblici.
Un sinonimo pu essere pubblico o privato. Un sinonimo privato pu
essere ovviamente utilizzato dallutente che lo ha creato, gli altri utenti
possono utilizzarlo solo se sono stati autorizzati e devono anteporre al nome
58
del sinonimo il nome dello schema in cui stato definito. Un sinonimo
pubblico pu essere utilizzato da tutti gli utenti del database senza anteporre
mai il nome di uno scema. Di fatto il sinonimo pubblico appartiene ad uno
schema speciale, pubblico appunto, i cui oggetti sono accessibili a chiunque
utilizzandone solo il nome.
I sinonimi non sono segment.
5.11.1 Procedure
Una procedura PL/SQL un programma registrato nel DB che accetta
un determinato numero di parametri di input/output ed esegue unattivit
senza tornare uno specifico valore al chiamante. Una procedura non pu
essere utilizzata in un comando SQL, ma solo in un altro PL/SQL.
5.11.2 Funzioni
Una funzione PL/SQL un programma registrato nel DB che accetta
un determinato numero di parametri di input/output ed esegue unattivit
tornando uno specifico valore al chiamante. Le funzioni possono essere
utilizzate anche allinterno dei comandi SQL a patto di non modificare nulla
nel database.
5.11.3 Package
Un Package PL/SQL un insieme di procedure, funzioni e variabili
PL/SQL che vengono riunite in un unico oggetto. Lorganizzazione degli
oggetti PL/SQL in package garantisce vari vantaggi che saranno approfonditi
nel capitolo dedicato al PL/SQL.
59
5.11.4 Trigger
Un Trigger un programma PL/SQL registrato nel DB ed associato ad
un evento. Il trigger non pu essere richiamato per lesecuzione
esplicitamente ma scatta automaticamente quando si verifica levento a cui
associato. Ad esempio possibile creare un trigger BEFORE INSERT sulla
tabella CLIENTI che scatta automaticamente subito prima dellinserimento di
qualunque record in tabella.
5.13 XML DB
Con la seconda release della versione 9 del DB Oracle ha introdotto
un insieme di nuove funzionalit che consentono di conservare nel db, e
manipolare molto pi semplicemente del passato, contenuti in formato XML.
Tali funzionalit sono accorpate sotto il nome di Oracle XML DB. Queste
caratteristiche sono state nelle versioni successive ulteriormente
implementate raggiungendo un buono stato di maturit e completezza. In
questo corso stato riservato allargomento il capitolo Errore. L'origine
riferimento non stata trovata.. In quel capitolo non ci si propone di
trattare il tema in modo organico, tale trattazione richiederebbe infatti troppo
spazio ed sicuramente al di l degli obiettivi di questo corso. Lobiettivo del
capitolo Errore. L'origine riferimento non stata trovata., invece, di
fornire alcuni spunti di riflessione relativi ad alcune specifiche tematiche che
accendano linteresse del lettore sullargomento.
Il database XML DB a partire dalla versione 12c un componente
obbligatorio, non pu essere disinstallato e non c alcuna opzione che
consenta di non includerlo quando si crea un nuovo database.
60
6 CASE STUDY
6.1 Progettazione
Unapplicazione software a tutti gli effetti un prodotto ingegneristico.
Nessuna persona sana di mente penserebbe di poter costruire un ponte o un
edificio senza prima averne fatto realizzare ad un professionista competente
un progetto completo. Nel mondo del software, invece, capita spesso di
cominciare a produrre, cio a scrivere il codice, senza avere prima condotto
una fase di progettazione completa e rigorosa oppure avendo affidato la fase
di progettazione a personale non sufficientemente qualificato. Questa
indubbiamente la causa della maggior parte dei fallimenti di progetti
informatici.
La progettazione di unapplicazione software, dunque, unattivit
molto delicata che rientra nel campo di studio di una scienza rigorosa detta
ingegneria del software.
Uno dei rami dellingegneria del software quello che definisce le
tecniche di progettazione dei database relazionali. Un approfondimento sulla
progettazione dei database relazionali sarebbe fuori contesto in questo
manuale. Un veloce accenno alla materia si pu trovare nel capitolo dei
prerequisiti( 10.2).
Lo schema tabellare descritto nel seguito in terza forma normale.
6.2.1 Tabelle
Per ogni tabella prevista fornito lelenco delle colonne. Per ogni
colonna viene indicato il nome, il tipo di dato, se la colonna obbligatoria, se
fa parte della chiave primaria, se fa parte di una chiave univoca, se fa parte
di una chiave esterna ed eventuali note. Il tipo di dato espresso utilizzando
i tipi Oracle descritti allinizio del prossimo capitolo.
CLIENTI
Nome Colonna Tipo Obbl. PK UK FK Note
COD_CLIENTE NUMBER(8) SI SI I valori di questa
colonna sono
generati
mediante la
sequenza
SEQ_CLIENTI
NOME VARCHAR2(30) SI
COGNOME VARCHAR2(30) SI
COD_FISC CHAR(16) SI
INDIRIZZO VARCHAR2(30) SI
CAP CHAR(5) SI
COMUNE CHAR(4) SI SI Referenzia la
tabella COMUNI
COMUNI
62
PRODOTTI
ORDINI
PRODOTTI_ORDINATI
63
FATTURE
Nome Colonna Tipo Obbl. PK UK FK Note
NUM_FATTURA NUMBER(8) SI SI I valori di questa
colonna sono generati
mediante la sequenza
SEQ_FATTURE
NUM_ORDINE NUMBER(8) SI SI Referenzia la tabella
ORDINI
DATA_FATTURA DATE SI
IMPORTO NUMBER(7,2) SI
PAGATA CHAR(1) SI Valori ammessi S, N
6.2.2 Dati
Una volta lanciati i due script sar creato uno schema denominato
WTO_ESEMPIO contenente tutte le tabelle sopra descritte ed i seguenti dati:
WTO >select * from clienti;
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
G811 POMEZIA RM
M297 FIUMICINO RM
F205 MILANO MI
G686 PIOLTELLO MI
E415 LAINATE MI
F839 NAPOLI NA
G964 POZZUOLI NA
G902 PORTICI NA
64
2 20-OTT-10 2 700
3 01-NOV-10 4 1000 Fattura differita 90gg
4 01-NOV-10 5 1200
5 01-DIC-10 7 1700
6.3 SCOTT/TIGER
Il database Oracle fornisce per default alcuni schemi desempio muniti
di alcune tabelle gi popolate. Questi schemi sono utili per i corsi di
formazione. Il pi famoso di questi schemi senzaltro SCOTT (password
tiger), presente fin dalle primissime versioni di Oracle.
Lutente SCOTT inizialmente ha laccount bloccato. Tentando di
connettersi a questo schema da SQL*Plus si otterr un errore.
WTO> conn scott/tiger
ERROR:
ORA-28000: the account is locked
Utente modificato.
65
WTO> select * from cat;
TABLE_NAME TABLE_TYPE
------------------------------ -----------
BONUS TABLE
DEPT TABLE
EMP TABLE
SALGRADE TABLE
14 rows selected.
66
7 SQL
67
Listruzione SELECT, che consente di leggere i dati dal database ma
non di modificarli, viene normalmente fatta rientrare nel linguaggio DML
sebbene forse sarebbe pi corretto considerarla in un insieme a se stante.
Nello spirito introduttivo di questo corso non si analizzeranno i
comandi SQL nel dettaglio di tutte le opzioni. Ci si limiter agli aspetti
principali utilizzati nella maggior parte dei casi. Per unanalisi dettagliata dei
comandi con riferimento a tutte le opzioni si rimanda alle 1508 pagine del
manuale SQL Language Reference scaricabile liberamente, come tutta la
documentazione del db, dal sito http://www.oracle.com/.
Negli esempi capiter talvolta di utilizzare comandi che ancora non
sono stati descritti. Si ricorso a questa soluzione quando si voleva subito
spiegare un concetto con un esempio senza rinviare ad un momento
successivo. In tutti questi casi i comandi utilizzati in anticipo sono molto
intuitivi e comunque commentati.
Tutti i comandi SQL sono case-insensitive, dunque possono essere
scritti indifferentemente in maiuscolo, in minuscolo o con una qualunque
mescolanza di caratteri minuscoli e maiuscoli. Le uniche parti delle istruzioni
che debbono essere considerate case-sensitive sono quelle che appaiono
racchiuse da apici singoli o doppi, ad esempio le due seguenti
Contenuto Case-Sensitive
Contenuto Case-Sensitive
69
mostra che la colonna stata automaticamente definita di tipo
VARCHAR2(3).
Come visto la lunghezza massima di un campo VARCHAR2 32767
caratteri. Laddove fosse necessario memorizzare stringhe alfanumeriche pi
lunghe possibile definire pi campi lunghi ognuno 4000 caratteri oppure
utilizzare il tipo CLOB che significa Character Long Object e pu contenere,
in un database standard con data block di 8K, fino a 32TB di dati. I campi
CLOB sono soggetti per ad alcune limitazioni:
Un campo CLOB non pu essere chiave primaria nella tabella.
Non pu essere incluso in un cluster di tabelle.
Non pu essere utilizzato nelle clausole ORDER BY e GROUP BY di una
SELECT.
Non pu essere utilizzato in una SELECT DISTINCT.
Non pu essere utilizzato in un indice standard.
Queste limitazioni sono ovviamente poco comprensibili in questa fase
del corso, ma saranno tutte chiare alla fine.
Prima dellintroduzione del tipo CLOB, avvenuta con Oracle 8, per
definire campi alfanumerici pi lunghi di 2000 caratteri bisognava utilizzare il
tipo LONG. Questo tipo di dato pu contenere fino a 2GB di caratteri ma
soggetto a forti limitazioni (ad esempio ce ne pu essere al massimo uno per
tabella). Il tipo LONG ancora presente per compatibilit con le vecchie
versioni del database ma se ne sconsiglia fortemente lutilizzo.
7.1.2 Numeri
Il tipo di dato principalmente utilizzato in Oracle per la conservazione
dei dati numerici NUMBER(P,S). P, la precisione, un numero che varia
da 1 a 38 e rappresenta il numero di cifre significative complessive,
includendo sia la parte intera che la parte decimale del numero. S, la scala,
un numero che varia da -84 a 127 ed indica la massima cifra frazionaria da
gestire. Se S assume un valore negativo si intende che non si vogliono
gestire cifre frazionarie n le S cifre intere meno significative. Ad esempio un
campo definito NUMBER(5,-2) potr contenere al massimo cinque cifre
significative e non conterr n cifre frazionarie n unit n decine. Sar
quindi un numero sempre arrotondato alle centinaia: 1234500, 400, 98700
Precisione e scala non devono essere obbligatoriamente indicate. In
particolare scrivere NUMBER(P) equivale a scrivere NUMBER(P,0) e
rappresenta un numero intero di massimo P cifre. Se non si specificano n P
n S si ottiene un numero a virgola mobile ( 10.5) (tutti i NUMBER(P,S)
visti finora sono a virgola fissa) che rappresenta il numero avente la massima
precisione e scala gestito in Oracle.
Nella tabella seguente sono elencati alcuni esempi di NUMBER con i
relativi valori positivi minimi e massimi.
70
Minimo numero Massimo numero
Tipo positivo positivo
rappresentabile rappresentabile
-130 126
NUMBER 10 <10
38
NUMBER(38) 1 <10
NUMBER(5,2) 0,01 999,99
NUMBER(5,-2) 100 9999900
NUMBER(3,8) 0,00000001 0,00000999
71
Anche questo tipo ancora presente per compatibilit con le vecchie versioni
ma se ne sconsiglia lutilizzo.
7.2.1 CREATE
Il comando CREATE si utilizza per definire nuovi oggetti di database. Il
comando ovviamente assume una forma diversa per ogni tipo di oggetto da
creare. Per ogni tipo di oggetto preso in considerazione nel capitolo 5 sar
fornito un esempio e saranno discusse le possibili varianti.
Quando si crea un oggetto sempre possibile definire lo schema in cui
si desidera che loggetto sia inserito anteponendo il nome dello schema al
nome delloggetto e separando i due nomi con un punto.
Ad esempio in fase di creazione di una tabella listruzione comincer
con
Create table <nome schema>.<nome tabella> (
Tabella creata.
72
impossibile leggerla utilizzando il nome test senza virgolette.
Successivamente viene definita la tabella TEST, in questo caso possibile
leggerla utilizzando il nome TEST senza virgolette.
WTO >create table "test" (a number);
Tabella creata.
Tabella creata.
Tra parentesi appare lelenco delle colonne della tabella. Per ogni
colonna bisogna obbligatoriamente indicare solo il nome ed il tipo.
Facoltativamente pu essere indicata lobbligatoriet della colonna (mediante
73
le clausole NULL o NOT NULL). Lassenza della clausola di obbligatoriet
equivale alla presenza della clausola NULL, quindi il campo non
obbligatorio.
A fronte di ogni colonna possibile indicare un valore di default, ci si
ottiene semplicemente aggiungendo dopo alla definizione della colonna la
clausola DEFAULT seguita da un valore. Nel caso in cui, durante
linserimento, non venga fornito alcun valore per una colonna munita di
valore di default, questa viene automaticamente inizializzata con il valore
indicato in fase di creazione. Largomento sar approfondito nellambito del
comando INSERT.
In molti database possibile indicare che una colonna deve essere
automaticamente popolata con una sequenza numerica. In Oracle ci non
possibile. Esistono, come gi detto, appositi oggetti di database che nascono
per generare sequenze numeriche, ma queste sequenze non possono
essere associate esplicitamente in fase di creazione della tabella ad una
colonna. Tale associazione deve essere fatta via programma, in PL/SQL o in
qualunque altro programma che possa effettuare operazioni SQL. Ci
torneremo quando tratteremo le sequenze ed i trigger PL/SQL.
Nel comando di creazione della tabella possibile specificare i
constraint che si intendono definire sui dati. Nellesempio che segue viene
creata una tabella TEST con le colonne A, B, C, D. La colonna A definita
come primary key, la colonna B come unique key, la colonna C come foreign
key verso la colonna C di unaltra tabella TEST2, sulla colonna D viene
definito un check constraint: la colonna ammetter solo valori maggiori di 3.
WTO >create table test (
2 a number primary key,
3 b number unique,
4 c number references test2(c),
5 d number check (d>3)
6 );
Tabella creata.
74
assumere che i dati che deve contenere. Nellesempio che segue viene
dapprima create una tabella TEST, poi mediante listruzione CREATE
TABLE AS SELECT si crea un duplicato identico della tabella
denominato TEST_COPY. Il comando DESC che chiude lesempio mostra la
struttura della tabella TEST_COPY.
WTO >create table test (
2 A number not null,
3 B varchar2(30),
4 C date
5 );
Tabella creata.
Tabella creata.
Tabella creata.
75
Creazione di un indice
La forma pi semplice dellistruzione di creazione di un indice la
seguente:
create index <nome schema>.<nome indice> ON <nome tabella>(
<nome colonna>,
<nome colonna>,
...
<nome colonna>
);
Indice creato.
Indice creato.
Indice creato.
Indice creato.
76
Creazione di una IOT
Una IOT, come gi detto, una ordinaria tabella relazionale che viene
archiviata in memoria sotto forma di indice, cio in una struttura di tipo B-
Tree. Per creare una IOT si utilizza listruzione CREATE TABLE seguita dalla
clausola ORGANIZATION INDEX.
Una IOT non pu esistere se sulla tabella non definita la primary key.
Nellesempio che segue si cerca dapprima di creare una IOT senza primary
key e poi si modifica listruzione aggiungendo la definizione del constraint.
WTO >create table test_iot (
2 A number not null,
3 B varchar2(30),
4 C date
5 )
6 organization index;
organization index
*
ERRORE alla riga 6:
ORA-25175: no PRIMARY KEY constraint
found
Tabella creata.
77
WTO >create cluster COMUNI_PROVINCE (
2 cod_provincia char(2)
3 ) SIZE 16384;
Creato cluster.
Indice creato.
Tabella creata.
Tabella creata.
Creato cluster.
Tabella creata.
78
WTO >create table PROVINCE (
2 id_pro char(2) not null primary key,
3 descrizione varchar2(100)
4 ) cluster COMUNI_PROVINCE (id_pro);
Tabella creata.
NOME COGNOME
---------- ----------
MARCO ROSSI
GIOVANNI BIANCHI
NOME COGNOME
---------- ----------
MARCO ROSSI
GIOVANNI BIANCHI
Vista creata.
80
WTO >create view clienti_roma as
2 select nome, cognome
3 from clienti
4 where comune='H501';
create view clienti_roma as
*
ERRORE alla riga 1:
ORA-00955: name is already used by an
existing object
Vista creata.
NOME COGNOME
---------- ----------
MARCO ROSSI
GIOVANNI BIANCHI
Aggiornata 1 riga.
81
WTO >select * from clienti_roma;
NOME COGNOME
---------- ----------
MASSIMO ROSSI
GIOVANNI BIANCHI
NOME COGNOME
---------- ----------
MARCO ROSSI
GIOVANNI BIANCHI
NOME COGNOME
---------- ----------
MASSIMO ROSSI
GIOVANNI BIANCHI
82
Nellesempio seguente viene creata una vista materializzata che ha
come START WITH listante di creazione pi un minuto e come NEXT
listante di creazione pi tre minuti. Di conseguenza la vista materializzata
viene aggiornata dopo un minuto dalla creazione e poi ogni due minuti.
La sintassi con cui si esprime listante di creazione della vista fa uso
della funzione SYSDATE che ritorna listante corrente (al secondo). A questa
vengono aggiunti i minuti come frazioni di giorni 1/(24*60) pari alla
1440esima parte di un giorno, cio un minuto.
WTO >create materialized view clienti_roma_mat
2 refresh start with sysdate+1/(24*60)
3 next sysdate+3/(24*60)
4 as
5 select nome, cognome
6 from clienti
7 where comune='H501';
NOME COGNOME
---------- ----------
MARCO ROSSI
GIOVANNI BIANCHI
Aggiornata 1 riga.
WTO >commit;
Commit completato.
NOME COGNOME
---------- ----------
MARCO ROSSI
GIOVANNI BIANCHI
NOME COGNOME
---------- ----------
MASSIMO ROSSI
GIOVANNI BIANCHI
83
vista materializzata non sarebbe stata aggiornata. Ad esempio eseguiamo
unaltra modifica del nome, trasformiamo MASSIMO in MASS ed aspettiamo
pi di due minuti:
WTO >update clienti
2 set nome='MASS'
3 where cognome='ROSSI';
Aggiornata 1 riga.
NOME COGNOME
---------- ----------
MASSIMO ROSSI
GIOVANNI BIANCHI
Commit completato.
NOME COGNOME
---------- ----------
MASS ROSSI
GIOVANNI BIANCHI
Sequenza creata.
84
WTO >select seq_test.nextval from dual;
NEXTVAL
----------
1
NEXTVAL
----------
2
NEXTVAL
----------
3
La tabella DUAL una tabella di sistema che ha una sola riga ed una
sola colonna. Torna molto utile in varie situazioni di cui si parler nel
prosieguo. Il valore corrente della sequenza si ottiene con la pseudocolonna
CURRVAL
WTO >select seq_test.currval from dual;
CURRVAL
----------
3
Sequenza creata.
NEXTVAL
----------
85
2
NEXTVAL
----------
4
NEXTVAL
----------
6
--ALTRE CHIAMATE PER PORTARE LA SEQUENZA A 46 SONO STATE OMESSE
WTO >select seq_test_pari.nextval from dual
NEXTVAL
----------
48
WTO >;
NEXTVAL
----------
50
NEXTVAL
----------
1
NEXTVAL
----------
3
Sequenza creata.
NEXTVAL
----------
2
NEXTVAL
86
----------
4
-- DOPO ALTRE CHIAMATE:
WTO > select seq_test_pari.nextval from dual
NEXTVAL
----------
48
NEXTVAL
----------
50
NEXTVAL
----------
2
NEXTVAL
----------
4
Sequenza creata.
NEXTVAL
----------
30
NEXTVAL
----------
29
NEXTVAL
----------
28
NEXTVAL
----------
1
87
NEXTVAL
----------
0
NEXTVAL
----------
-1
NEXTVAL
----------
-2
Sequenza creata.
NEXTVAL
----------
1
NEXTVAL
----------
2
NEXTVAL
----------
3
NEXTVAL
----------
1
88
Creazione di un sinonimo
Un sinonimo solo un nome alternativo che scegliamo di utilizzare per
un oggetto del db. La sintassi banale
CREATE SYNONYM <nome schema>.<nome sinonimo>
FOR <nome schema>.<nome oggetto>;
Sinonimo creato.
WTO >desc c
Nome Nullo? Tipo
----------------------- -------- ---------------
COD_CLIENTE NOT NULL NUMBER(8)
NOME NOT NULL VARCHAR2(30)
COGNOME NOT NULL VARCHAR2(30)
COD_FISC CHAR(16)
INDIRIZZO NOT NULL VARCHAR2(30)
CAP NOT NULL CHAR(5)
COMUNE NOT NULL CHAR(4)
Sinonimo creato.
WTO >desc c2
Nome Nullo? Tipo
----------------- -------- ------------
COD_CLIENTE NOT NULL NUMBER(8)
NOME NOT NULL VARCHAR2(30)
COGNOME NOT NULL VARCHAR2(30)
COD_FISC CHAR(16)
INDIRIZZO NOT NULL VARCHAR2(30)
CAP NOT NULL CHAR(5)
COMUNE NOT NULL CHAR(4)
89
Connesso.
WTO >desc c
ERROR:
ORA-04043: object c does not exist
WTO >desc c2
Nome Nullo? Tipo
----------------- -------- ------------
COD_CLIENTE NOT NULL NUMBER(8)
NOME NOT NULL VARCHAR2(30)
COGNOME NOT NULL VARCHAR2(30)
COD_FISC CHAR(16)
INDIRIZZO NOT NULL VARCHAR2(30)
CAP NOT NULL CHAR(5)
COMUNE NOT NULL CHAR(4)
90
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
7.2.2 ALTER
Il comando ALTER consente di modificare alcuni dei parametri degli
oggetti gi creati senza modificarne il contenuto. Nel seguito sono discusse
ed esemplificate alcune delle attivit per cui, pi comunemente, si ricorre al
comando ALTER.
Aggiungere, modificare, rinominare, eliminare le colonne di una
tabella
Per aggiungere colonne ad una tabella si utilizza il comando
ALTER TABLE <nome schema>.<nome tabella> ADD (
<nome colonna> <tipo colonna> <null/not null>,
<nome colonna> <tipo colonna> <null/not null>,
...
<nome colonna> <tipo colonna> <null/not null>
);
Tabella creata.
Tabella modificata.
Tabella modificata.
Tabella modificata.
92
length because some value is too big
Ad esempio:
WTO >desc test
Nome Nullo? Tipo
----------------- -------- ------------
A NOT NULL NUMBER
B VARCHAR2(10)
C NOT NULL NUMBER
D NUMBER
E DATE
Tabella modificata.
Ad esempio:
WTO >alter table test drop column d;
Tabella modificata.
93
NUOVA_A NOT NULL NUMBER
B VARCHAR2(10)
C NOT NULL NUMBER
E DATE
Tabella modificata.
Tabella modificata.
Tabella creata.
Tabella modificata.
Tabella modificata.
Tabella troncata.
Creata 1 riga.
94
NUOVA_A NOT NULL NUMBER
B VARCHAR2(10)
C NOT NULL NUMBER
X NUMBER
Y NUMBER
E DATE
A B
---------- ------------------------------
1 sabato
2 domenica
3 luned
4 marted
5 mercoled
6 gioved
7 venerd
7 righe selezionate.
Tabella modificata.
O12c>desc test_invisibili
Nome Nullo? Tipo
----------------- -------- ------------
A NOT NULL NUMBER
A
----------
1
2
3
95
4
5
6
7
7 righe selezionate.
A B
---------- --------------------
1 sabato
2 domenica
3 luned
4 marted
5 mercoled
6 gioved
7 venerd
7 righe selezionate.
Tabella modificata.
A B
---------- --------------------
1 sabato
2 domenica
3 luned
4 marted
5 mercoled
6 gioved
7 venerd
7 righe selezionate.
96
(
FOREIGN KEY <nome colonna>,
<nome colonna>,
...
<nome colonna>
) REFERENCES <nome tabella> (
<nome colonna>,
<nome colonna>,
...
<nome colonna>
)
(
UNIQUE <nome colonna>,
<nome colonna>,
...
<nome colonna>
)
(<regola>)
CHECK
Quattro esempi per chiarire:
Aggiunta della PRIMARY KEY
WTO >ALTER TABLE TEST ADD
2 CONSTRAINT TEST_PK PRIMARY KEY (NUOVA_A);
Tabella modificata.
Tabella creata.
Tabella modificata.
Tabella modificata.
Tabella modificata.
97
Non possibile modificare la definizione di un constraint. Per
cambiarne lo stato (abilitato/disabilitato) si utilizza la clausola MODIFY
ENABLE/DISABLE. Nellesempio seguente si crea una tabella TEST_DUP
contenente una sola colonna X. X primary key della tabella e quindi
univoca. Il tentativo di inserire due valori uguali causa chiaramente un errore.
A questo punto il constraint viene disabilitato e si procede senza errori
allinserimento di valori duplicati. Quando si cerca di abilitare il constraint si
ottiene un errore, successivamente i valori duplicati vengono rimossi ed il
constraint viene correttamente riabilitato.
--CREAZIONE DELLA TABELLA
WTO >create table test_dup (x number);
Tabella creata.
Tabella modificata.
Creata 1 riga.
Tabella modificata.
Creata 1 riga.
X
----------
1
1
98
alter table test_dup modify constraint x_pk enable
*
ERRORE alla riga 1:
ORA-02437: cannot validate
(WTO_ESEMPIO.X_PK) - primary key
violated
Eliminata 1 riga.
X
----------
1
Ad esempio
WTO >alter table TEST_DUP rename constraint X_PK to NUOVO_X_PK;
Tabella modificata.
Ad esempio
WTO >alter table TEST_DUP drop constraint NUOVO_X_PK;
Tabella modificata.
Creato cluster.
99
--CREAZIONE DI UN INDEXED CLUSTER
WTO >create cluster COMUNI_PROVINCE_2 (
2 cod_provincia char(2)
3 ) SIZE 16384;
Creato cluster.
Modificato cluster.
Modificare un indice
Nessuno dei parametri degli indici analizzati in precedenza pu essere
modificato con lALTER INDEX. Il comando seguente pu essere utilizzato
per rinominare lindice.
WTO >create index test_idx on test (c,x);
Indice creato.
Modificato indice.
Modificare un sinonimo
100
Non esiste il comando ALTER SYNONYM, si utilizza la clausola OR
REPLACE dopo la CREATE.
Modificare una sequenza
Il comando ALTER SEQUENCE (senza parole chiave aggiuntive)
consente di modificare tutti i parametri gi descritti in fase di creazione delle
sequenze ad eccezione del valore di partenza, che era stato definito
mediante la clausola START WITH. Ad esempio nellistruzione che segue si
modifica la sequenza SEQ_TEST, originariamente impostata per fornire un
progressivo numerico crescente senza buchi, per ottenere un progressivo di
numeri che si incrementi di tre unit ad ogni chiamata.
WTO >select seq_test.nextval from dual;
NEXTVAL
----------
5
NEXTVAL
----------
6
Sequenza modificata.
NEXTVAL
----------
9
7.2.3 RENAME
Il comando RANAME consente di rinominare un oggetto di database.
Questo comando si applica solo a tabelle, viste, sequenze e sinonimi privati.
La sintassi banale.
RENAME <nome schema>.<vecchio nome> to <nome schema>.<nuovo nome>
--UNA TABELLA
101
WTO >rename test to new_test;
Tabella rinominata.
--UNA VISTA
WTO >rename clienti_roma to new_clienti_roma;
Tabella rinominata.
--UNA SEQUENZA
WTO >rename seq_test to seq_test_new;
Tabella rinominata.
Tabella rinominata.
7.2.4 DROP
Il comando generico per eliminare un oggetto di database il
seguente:
DROP <tipo oggetto> <nome schema>.<nome oggetto>
--UNA TABELLA
WTO >drop table NEW_TEST;
Tabella eliminata.
--UN INDICE
WTO >drop index TEST_IDX;
Indice eliminato.
--UNA VISTA
WTO >drop view CLIENTI_ROMA;
Vista eliminata.
Eliminato cluster.
--UNA IOT
WTO >drop table TEST_IOT;
Tabella eliminata.
102
--UN SINONIMO PRIVATO
WTO >drop synonym C_NEW;
Sinonimo eliminato.
Sinonimo eliminato.
In aggiunta a questo comando generale, valido per tutti gli oggetti del
database, si possono utilizzare alcune clausole specifiche per alcuni tipi di
oggetto.
Eliminazione di una tabella referenziata in una foreign key
Nel caso di eliminazione di una tabella, pu succedere che essa sia
referenziata da un constraint di foreign key definito su unaltra tabella. Negli
esempi precedenti si era definita, ad esempio, una foreign key tra la tabella
TEST e la tabella TEST2.
In questa situazione non possibile eliminare la tabella TEST2 con il
comando standard.
WTO >drop table test2;
Tabella eliminata.
Tabella modificata.
Tabella eliminata.
103
Eliminazione di un cluster non vuoto
Se in un cluster di tabelle stata aggiunta almeno una tabella non
sar possibile eliminarlo.
WTO >drop cluster COMUNI_PROVINCE;
drop cluster COMUNI_PROVINCE
*
ERRORE alla riga 1:
ORA-00951: cluster not empty
Eliminato cluster.
Tabella eliminata.
Tabella eliminata.
Eliminato cluster.
7.2.5 TRUNCATE
Il comando TRUNCATE consente di eliminare in modo rapido lintero
contenuto di una tabella o di un cluster di tabelle senza modificarne la
struttura. Il comando non annullabile ma automaticamente confermato. Il
comando TRUNCATE generalmente pi rapido del comando DML
DELETE che sar illustrato pi avanti.
Troncamento di una tabella
Listruzione di troncamento di una tabella
TRUNCATE TABLE <nome schema>.<nome tabella>
Ad esempio:
WTO >truncate table test;
Tabella troncata.
104
Un HASH cluster non pu essere troncato.
--CREO UN HASH CLUSTER...
WTO >create cluster COMUNI_PROVINCE (
2 cod_provincia char(2)
3 ) SIZE 16384 HASHKEYS 103;
Creato cluster.
Eliminato cluster.
Creato cluster.
Cluster troncato.
Tabella creata.
Creata 1 riga.
Poi la figlia:
O12c>create table figlio (id number, id_pa number);
Tabella creata.
Creata 1 riga.
Tabella modificata.
Tabella modificata.
Tabella modificata.
106
7.2.6 PURGE
Quando si elimina un oggetto segment Oracle lo conserva nel cestino,
come quando si cancella un file in windows.
Loggetto viene rinominato con un nome di sistema e conservato.
Leffetto delle cancellazioni eseguite negli esempi precedenti il
seguente:
WTO >select * from cat;
TABLE_NAME TABLE_TYPE
------------------------------ -----------
TEST_COPY TABLE
COMUNI TABLE
SEQ_TEST_PARI SEQUENCE
X SEQUENCE
SEQ_DESC SEQUENCE
CLIENTI TABLE
SEQ_CLIENTI SEQUENCE
PRODOTTI TABLE
ORDINI TABLE
SEQ_ORDINI SEQUENCE
PRODOTTI_ORDINATI TABLE
FATTURE TABLE
SEQ_FATTURE SEQUENCE
TEST_PRE_MODIFICA TABLE
TEST_DUP TABLE
123TesTVirgo@++ TABLE
TEST TABLE
NEW_CLIENTI_ROMA VIEW
SEQ_TEST_NEW SEQUENCE
BIN$HzDBX3YoS3m9RX5c+xg2/w==$0 TABLE
BIN$H30bMxKuQput74HcB1GXcA==$0 TABLE
BIN$d8Hp3XYlS1G0xuBp0rYIhA==$0 TABLE
BIN$Sw7y9bgbQLSkwfEM+SLAnA==$0 TABLE
Selezionate 23 righe.
Le quattro tabelle poste alla fine dellelenco sono appunto oggetti finiti
nel cestino a fronte di comandi DROP.
Un elenco pi preciso degli oggetti presenti nel cestino pu essere
ottenuto con il comando che si vede nellesempio seguente.
Le informazioni sono estratte dalla tabella di dizionario
USER_RECYCLEBIN.
WTO >select OBJECT_NAME, original_name, type
2 from user_recyclebin;
107
Per svuotare il cestino parzialmente o totalmente e recuperare
definitivamente lo spazio si utilizza il comando PURGE.
In particolare il comando
PURGE TABLE <nome tabella>
Svuotata tabella.
Svuotato indice.
Svuotato cestino.
--INSERIMENTO DI UN RECORD
WTO >insert into TEST_FLASHBACK values (123);
Creata 1 riga.
A
----------
123
108
--ELIMINAZIONE DELLA TABELLA
WTO >drop table TEST_FLASHBACK;
Tabella eliminata.
Completato flashback.
A
----------
123
7.3.2 INSERT
Il comando INSERT consente di inserire record in una tabella. Il
comando pu essere utilizzato nella forma pi semplice seguente:
INSERT INTO <nome schema>.<nome tabella>
VALUES (<valore>, <valore>, ..., <valore>);
Tabella eliminata.
Tabella creata.
Creata 1 riga.
A B C
---------- --------- ------------------------------
123,4 13-GEN-11 Stringa d'esempio
110
Ovviamente tale sintassi ci costringe a fornire valori per tutte le
colonne della tabella. Se, infatti, forniamo solo due valori anzich i tre previsti
otteniamo un errore:
WTO >insert into test values (123.4, date'2011-01-13');
insert into test values (123.4, date'2011-01-13')
*
ERRORE alla riga 1:
ORA-00947: not enough values
Creata 1 riga.
A B C
---------- --------- ------------------------------
123,4 13-GEN-11 Stringa d'esempio
123,4 13-GEN-11
Creata 1 riga.
A B C
---------- --------- ------------------------------
123,4 13-GEN-11 Stringa d'esempio
123,4 13-GEN-11
0 Test
Creata 1 riga.
A B C
---------- --------- ------------------------------
123,4 13-GEN-11 Stringa d'esempio
123,4 13-GEN-11
0 Test
Test con campi nulli
111
Nellesempio presedente, sebbene tutte le tre colonne fossero inserite
nella clausola INTO, si scelto di valorizzare la sola colonna C.
Inserimento dati e valori di default
Vediamo cosa succede quando una colonna munita di valore di
default. Definiamo la tabella TEST_DEFAULT avente due colonne, A un
numero, B una stringa con valore di default.
WTO >create table test_default (
2 a number,
3 b varchar2(30) default 'Valore di default'
4 );
Tabella creata.
Creata 1 riga.
A B
---------- ------------------------------
1 Test
Creata 1 riga.
A B
---------- ------------------------------
1 Test
2 Valore di default
Creata 1 riga.
A B
---------- ------------------------------
1 Test
2 Valore di default
3
112
Se si desidera che una colonna munita di valore di default sia anche
menzionata nella clausola INTO ed assuma il valore di default bisogna usare
la parola chiave DEFAULT al poste del valore:
WTO >insert into test_default (A,B)
2 values (4, default);
Creata 1 riga.
A B
---------- ------------------------------
1 Test
2 Valore di default
3
4 Valore di default
Fino ad Oracle 11g, il valore di default di una colonna non mai stato
applicato quando lutente (o lapplicazione) inseriva esplicitamente il valore
NULL.
SQL >create table test_default (
2 a number,
3 b varchar2(30) default 'Valore di default'
4 );
Tabella creata.
A B
---------- ------------------------------
3
Tabella creata.
A B
---------- ------------------------------
3 Valore di default
113
A partire da Oracle 12c, quando una colonna non valorizzata, il suo
eventuale valore di default conservato nel data dictionary e non nella
tabella stessa, come invece avveniva nelle precedenti versioni di Oracle.
Laggiunta di nuove colonne munite di default quindi molto pi
veloce, visto che non richiede di scrivere fisicamente il valore di default in
tutti i record gi presenti in tabella.
Partiamo dalla tabella TEST_TAB valorizzata come segue:
O12c>select * from test_tab;
ID DESCR
---------- ------------------------------
1 riga 1
2 riga 2
3 riga 3
4 riga 4
5 riga 5
6 riga 6
7 riga 7
8 riga 8
9 riga 9
10 riga 10
11 riga 11
12 riga 12
13 riga 13
14 riga 14
15 riga 15
16 riga 16
17 riga 17
18 riga 18
19 riga 19
20 riga 20
20 righe selezionate.
Tabella modificata.
ID DESCR X
---------- ------------------------------ ---
1 riga 1 ABC
2 riga 2 ABC
3 riga 3 ABC
4 riga 4 ABC
5 riga 5 ABC
6 riga 6 ABC
7 riga 7 ABC
8 riga 8 ABC
9 riga 9 ABC
10 riga 10 ABC
11 riga 11 ABC
12 riga 12 ABC
13 riga 13 ABC
114
14 riga 14 ABC
15 riga 15 ABC
16 riga 16 ABC
17 riga 17 ABC
18 riga 18 ABC
19 riga 19 ABC
20 riga 20 ABC
20 righe selezionate.
Aggiornata 1 riga.
ID DESCR X
---------- ------------------------------ ---
1 riga 1 ABC
2 riga 2 ABC
3 riga 3 ABC
4 riga 4 ABC
5 riga 5 ABC
6 riga 6 ABC
7 riga 7 ABC
8 riga 8 ABC
9 riga 9 ABC
10 riga 10 ABC
11 riga 11 ABC
12 riga 12 ABC
13 riga 13 ABC
14 riga 14 ABC
15 riga 15 ABC
16 riga 16 ABC
17 riga 17 XYZ
18 riga 18 ABC
19 riga 19 ABC
20 riga 20 ABC
20 righe selezionate.
ID DESCR X
---------- ------------------------------ ---
1 riga 1 ABC
2 riga 2 ABC
3 riga 3 ABC
4 riga 4 ABC
115
5 riga 5 ABC
6 riga 6 ABC
7 riga 7 ABC
8 riga 8 ABC
9 riga 9 ABC
10 riga 10 ABC
11 riga 11 ABC
12 riga 12 ABC
13 riga 13 ABC
14 riga 14 ABC
15 riga 15 ABC
16 riga 16 ABC
17 riga 17 XYZ
18 riga 18 ABC
19 riga 19 ABC
20 riga 20 ABC
20 righe selezionate.
ID DESCR X
---------- ------------------------------ ---
1 riga 1
2 riga 2
3 riga 3
4 riga 4
5 riga 5
6 riga 6
7 riga 7 ABC
8 riga 8 ABC
9 riga 9 ABC
10 riga 10 ABC
11 riga 11 ABC
12 riga 12 ABC
13 riga 13 ABC
14 riga 14 ABC
15 riga 15 ABC
16 riga 16 ABC
17 riga 17 XYZ
18 riga 18 ABC
19 riga 19 ABC
20 riga 20 ABC
20 righe selezionate.
ID DESCR X
---------- ------------------------------ ---
1 riga 1
2 riga 2
3 riga 3
4 riga 4
5 riga 5
6 riga 6
7 riga 7 ABC
8 riga 8 ABC
116
9 riga 9 ABC
10 riga 10 ABC
11 riga 11 ABC
12 riga 12 ABC
13 riga 13 ABC
14 riga 14 ABC
15 riga 15 ABC
16 riga 16 ABC
17 riga 17 XYZ
18 riga 18 ABC
19 riga 19 ABC
20 riga 20 ABC
20 righe selezionate.
Sequenza creata.
Tabella creata.
20 righe create.
Con una query verifico che la sequence stata utilizzata per popolare
lID:
O12c>select * from test_seq_tab;
ID DESCR
---------- ------------------------------
1 riga 1
2 riga 2
117
3 riga 3
4 riga 4
5 riga 5
6 riga 6
7 riga 7
8 riga 8
9 riga 9
10 riga 10
11 riga 11
12 riga 12
13 riga 13
14 riga 14
15 riga 15
16 riga 16
17 riga 17
18 riga 18
19 riga 19
20 riga 20
20 righe selezionate.
CURRVAL
----------
20
Tabella creata.
7 righe create.
118
A B
---------- ------------------------------
1 sabato
2 domenica
3 luned
4 marted
5 mercoled
6 gioved
7 venerd
7 righe selezionate.
SEQUENCE_NAME
---------------------------------------------------
ISEQ$$_92470
TEST_SEQ
CURRVAL
----------
7
Tabella creata.
119
2 select * from test;
Create 4 righe.
WTO >select * from test2;
D E F
--------- ---------- ------------------------------
13-GEN-11 123,4 Stringa d'esempio
13-GEN-11 123,4
0 Test
Test con campi nulli
Create 4 righe.
D E F
--------- ---------- ------------------------------
13-GEN-11 123,4 Stringa d'esempio
13-GEN-11 123,4
0 Test
Test con campi nulli
13-GEN-11 123,4 Stringa d'esempio
13-GEN-11 123,4
0 Test
Test con campi nulli
Selezionate 8 righe.
120
D E F
--------- ---------- ------------------------------
13-GEN-11 123,4 Stringa d'esempio
13-GEN-11 123,4
0 Test
Test con campi nulli
13-GEN-11 123,4 Stringa d'esempio
13-GEN-11 123,4
0 Test
Test con campi nulli
13-GEN-11 123,4 Stringa d'esempio
13-GEN-11 123,4
0 Test
Test con campi nulli
Selezionate 12 righe.
G H I
---------- --------- ------------------------------
123,4 13-GEN-11 Stringa d'esempio
123,4 13-GEN-11
0 Test
Test con campi nulli
A B C
---------- --------- ------------------------------
123,4 13-GEN-11 Stringa d'esempio
123,4 13-GEN-11
0 Test
Test con campi nulli
121
G H I
---------- --------- ------------------------------
124,4 14-GEN-11 Stringa d'esempio
124,4 14-GEN-11
1 Test
Test con campi nulli
125,4 15-GEN-11 Stringa d'esempio
125,4 15-GEN-11
2 Test
Test con campi nulli
Selezionate 8 righe.
Tabella creata.
Creata 1 riga.
Creata 1 riga.
Creata 1 riga.
Creata 1 riga.
NOME DATA_NASC S
---------- --------- -
Massimo 01-NOV-71 M
Laura 09-MAR-00 F
122
Marco 23-AGO-90 M
Clara 18-APR-95 F
Vista creata.
NOME DATA_NASC S
---------- --------- -
Massimo 01-NOV-71 M
Marco 23-AGO-90 M
Creata 1 riga.
NOME DATA_NASC S
---------- --------- -
Massimo 01-NOV-71 M
Marco 23-AGO-90 M
NOME DATA_NASC S
---------- --------- -
Massimo 01-NOV-71 M
Laura 09-MAR-00 F
Marco 23-AGO-90 M
Clara 18-APR-95 F
Veronica 26-FEB-80 F
Vista creata.
123
Non possibile inserire un record femmina in tabella attraverso la
vista MASCHI. ovviamente sempre possibile inserire direttamente in
tabella.
WTO >insert into persone values
2 ('Vittoria',date'1987-05-10','F');
Creata 1 riga.
NOME DATA_NASC S
---------- --------- -
Massimo 01-NOV-71 M
Laura 09-MAR-00 F
Marco 23-AGO-90 M
Clara 18-APR-95 F
Veronica 26-FEB-80 F
Vittoria 10-MAG-87 F
Selezionate 6 righe.
7.3.3 UPDATE
Il comando UPDATE consente di modificare i dati presenti in una
tabella. La sintassi del comando la seguente:
UPDATE <nome schema>.<nome tabella>
SET <nome colonna> = <valore>,
<nome colonna> = <valore>,
...
<nome colonna> = <valore>
WHERE <condizione>
;
NOME DATA_NASC S
---------- --------- -
Massimo 01-NOV-71 M
Laura 09-MAR-00 F
Marco 23-AGO-90 M
Clara 18-APR-95 F
Veronica 26-FEB-80 F
Vittoria 10-MAG-87 F
Selezionate 6 righe.
124
WTO >update persone
2 set data_nascita = date'2000-01-12';
Aggiornate 6 righe.
WTO >select * from persone;
NOME DATA_NASC S
---------- --------- -
Massimo 12-GEN-00 M
Laura 12-GEN-00 F
Marco 12-GEN-00 M
Clara 12-GEN-00 F
Veronica 12-GEN-00 F
Vittoria 12-GEN-00 F
Selezionate 6 righe.
Aggiornata 1 riga.
NOME DATA_NASC S
---------- --------- -
Massimo 12-GEN-00 M
Laura 12-GEN-00 F
Marco 12-GEN-00 M
Clara 12-GEN-00 F
Veronica 12-GEN-00 F
Vittoria 10-MAG-87 F
Selezionate 6 righe.
Aggiornate 6 righe.
NOME DATA_NASC S
---------- --------- -
Massimo 13-GEN-00 M
Laura 13-GEN-00 F
Marco 13-GEN-00 M
Clara 13-GEN-00 F
Veronica 13-GEN-00 F
Vittoria 11-MAG-87 F
125
Selezionate 6 righe.
7.3.4 DELETE
Il comando per cancellare righe da una tabella assume la forma
DELETE FROM <nome schema>.<nome tabella>
WHERE <condizione>
;
NOME DATA_NASC S
---------- --------- -
Massimo 13-GEN-00 M
Laura 13-GEN-00 F
Marco 13-GEN-00 M
Clara 13-GEN-00 F
Veronica 13-GEN-00 F
Vittoria 11-MAG-87 F
Selezionate 6 righe.
Eliminate 2 righe.
NOME DATA_NASC S
---------- --------- -
Laura 13-GEN-00 F
Clara 13-GEN-00 F
Veronica 13-GEN-00 F
Vittoria 11-MAG-87 F
126
WTO >select * from persone;
Nessuna riga selezionata
7.3.5 MERGE
Listruzione MERGE consente di eseguire in un unico comando un
UPDATE ed un INSERT. possibile infatti specificare una condizione e, a
seconda del fatto che questa condizione sia vera o falsa, inserire un nuovo
record in tabella oppure aggiornarne uno gi esistente.
Come esempio duso si ipotizzi di avere la necessit di dover
aggiornare una tabella periodicamente leggendo i dati da un'altra tabella.
Si ipotizzi anche che i dati nella tabella sorgente siano completi, cio
che ci siano sia i record che abbiamo gi caricato con inserimenti precedenti
(e magari ora vanno aggiornati) sia nuovi record.
L'approccio pi semplice sicuramente quello di svuotare la tabella ad
ogni aggiornamento e riempirla rileggendo tutti i dati. Non sempre, per,
l'approccio migliore. Se invece vogliamo inserire i nuovi record ed aggiornare
soltanto quelli gi presenti possiamo utilizzare l'istruzione MERGE, che in
pratica racchiude la possibilit di eseguire, a seconda dei record, un INSERT
oppure un UPDATE.
Vediamo un esempio. Nello schema SCOTT ipotizziamo di dover
aggiornare la lista dei dipendenti (una nuova tabella MYEMP strutturalmente
identica alla EMP) leggendo la tabella EMP.
WTO> select * from emp;
127
7844 TURNER SALESMAN 7698 08-SET-81 1500 0 30
7876 ADAMS CLERK 7788 12-GEN-83 1100 20
7900 JAMES CLERK 7698 03-DIC-81 950 30
7902 FORD ANALYST 7566 03-DIC-81 3000 20
7934 MILLER CLERK 7782 23-GEN-82 1300 10
Selezionate 11 righe.
14 di righe unite.
Selezionate 14 righe.
129
3 ON (emp.empno=myemp.empno)
4 WHEN MATCHED THEN
5 UPDATE SET
6 ename = emp.ename,
7 job = emp.job,
8 mgr = emp.mgr,
9 hiredate = emp.hiredate,
10 sal = emp.sal,
11 comm = emp.comm,
12 deptno = emp.deptno
13 DELETE WHERE sal < 1000
14 WHEN NOT MATCHED THEN
15 INSERT (empno, ename, job, mgr, hiredate, sal, comm, deptno)
16 VALUES (emp.empno,emp.ename, emp.job, emp.mgr, emp.hiredate,
17 emp.sal, emp.comm, emp.deptno)
18 ;
14 di righe unite.
Selezionate 13 righe.
130
4 WHEN MATCHED THEN
5 UPDATE SET
6 ename = emp.ename,
7 job = emp.job,
8 mgr = emp.mgr,
9 hiredate = emp.hiredate,
10 sal = emp.sal,
11 comm = emp.comm,
12 deptno = emp.deptno
13 WHEN NOT MATCHED THEN
14 INSERT (empno, ename, job, mgr, hiredate, sal, comm, deptno)
15 VALUES (emp.empno,emp.ename, emp.job, emp.mgr, emp.hiredate,
16 emp.sal, emp.comm, emp.deptno)
17 WHERE emp.sal>1000
18 ;
13 righe unite.
Selezionate 13 righe.
131
Negli esempi che seguono si parler sempre di INSERT, ma tutto ci
che sar mostrato valido alla stessa maniera anche per le altre istruzioni
DML.
Connettendoci con lo schema SCOTT, ipotizziamo di voler travasare i
record della tabella EMP in una nuova tabella EMP2 fatta come segue:
WTO> desc emp
Name Null? Type
-------------------------- -------- ----------------------------
EMPNO NOT NULL NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NUMBER(2)
LENGTH(ENAME) COUNT(0)
------------- ----------
6 3
5 8
4 3
COUNT(*) COUNT(COMM)
---------- -----------
14 4
COUNT(0)
----------
12
133
default ERR$_ seguito dai primi 25 caratteri del nome della tabella in cui si
cerca di inserire.
Nel nostro caso, dunque, Oracle cerca di inserire gli errori nella tabella
ERR$_EMP2 che non esiste.
Come si crea la tabella di gestione degli errori?
Utilizzando il package DBMS_ERRLOG che ha un'unica procedura
CREATE_ERROR_LOG:
WTO> desc DBMS_ERRLOG
PROCEDURE CREATE_ERROR_LOG
Argument Name Type In/Out Default?
------------------------------ ----------- ------ --------
DML_TABLE_NAME VARCHAR2 IN
ERR_LOG_TABLE_NAME VARCHAR2 IN DEFAULT
ERR_LOG_TABLE_OWNER VARCHAR2 IN DEFAULT
ERR_LOG_TABLE_SPACE VARCHAR2 IN DEFAULT
SKIP_UNSUPPORTED BOOLEAN IN DEFAULT
2 rows created.
COUNT(0)
----------
12
Due righe sono state correttamente travasate, dodici errori sono stati
loggati nella tabella ERR$_EMP2.
Vediamo il contenuto della tabella degli errori, cominciamo con le
colonne di sistema. Visualizziamo in questesempio solo il messaggio
derrore:
WTO> select ORA_ERR_MESG$
2* from ERR$_EMP2
ORA_ERR_MESG$
------------------------------------------------------------
ORA-12899: value too large for column "SCOTT"."EMP2"."ENAME"
ORA-01400: cannot insert NULL into ("SCOTT"."EMP2"."COMM")
ORA-01400: cannot insert NULL into ("SCOTT"."EMP2"."COMM")
ORA-01400: cannot insert NULL into ("SCOTT"."EMP2"."COMM")
ORA-01400: cannot insert NULL into ("SCOTT"."EMP2"."COMM")
ORA-12899: value too large for column "SCOTT"."EMP2"."ENAME"
ORA-01400: cannot insert NULL into ("SCOTT"."EMP2"."COMM")
ORA-01400: cannot insert NULL into ("SCOTT"."EMP2"."COMM")
ORA-01400: cannot insert NULL into ("SCOTT"."EMP2"."COMM")
ORA-12899: value too large for column "SCOTT"."EMP2"."ENAME"
ORA-01400: cannot insert NULL into ("SCOTT"."EMP2"."COMM")
ORA-01400: cannot insert NULL into ("SCOTT"."EMP2"."COMM")
12 rows selected.
135
ORA_ERR_OPTYP$: il tipo di operazione (insert (I), update (U), delete
(D))
ORA_ERR_TAG$: un tag che opzionalmente possibile indicare nella
clausola LOG ERRORS per identificare meglio i record nella tabella degli
errori
Per ogni record rigettato c' un solo errore, anche su quelli che
avrebbero avuto pi di un motivo per essere scartati.
Per valorizzare il campo ORA_ERR_TAG$ si fa come segue:
WTO> insert into emp2
2 select * from emp
3 log errors ('ins2') reject limit 20;
2 rows created.
ORA_ERR_TAG$ COUNT(0)
------------------------------ ----------
12
ins2 12
2 rows created.
ORA_ERR_TAG$ COUNT(0)
------------------------------ ----------
12
2010-02-05 18:54:31 12
ins2 12
136
----- ---------- ---------- ----- ---------- ------ ------ ------
7369 SMITH CLERK 7902 17-DEC-80 800 20
7566 JONES MANAGER 7839 02-APR-81 2975 20
7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30
7698 BLAKE MANAGER 7839 01-MAY-81 2850 30
7782 CLARK MANAGER 7839 09-JUN-81 2450 10
7788 SCOTT ANALYST 7566 19-APR-87 3000 20
7839 KING PRESIDENT 17-NOV-81 5000 10
7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30
7876 ADAMS CLERK 7788 23-MAY-87 1100 20
7900 JAMES CLERK 7698 03-DEC-81 950 30
7902 FORD ANALYST 7566 03-DEC-81 3000 20
7934 MILLER CLERK 7782 23-JAN-82 1300 10
12 rows selected.
Selezionate 8 righe.
7.4.1 Proiezioni
Partendo dal comando base sopra illustrato, il primo raffinamento
dellistruzione la scelta delle colonne da visualizzare. Tale query, detta
137
anche proiezione della tabella, si realizza specificando le colonne che si
desiderano estrarre, separate da virgola.
Nellesempio seguente si estraggono solo le colonne COGNOME ed
INDIRIZZO della tabella CLIENTI.
WTO >select cognome, indirizzo from clienti;
COGNOME INDIRIZZO
-------- ----------------------
ROSSI VIA LAURENTINA, 700
BIANCHI VIA OSTIENSE, 850
VERDI VIA DEL MARE, 8
NERI VIA TORINO, 30
COLOMBO PIAZZA DUOMO, 1
ESPOSITO VIA CARACCIOLO, 100
RUSSO VIA GIULIO CESARE, 119
AMATO VIA NAPOLI, 234
Selezionate 8 righe.
C I
------------------------------ -----------------------------
ROSSI VIA LAURENTINA, 700
BIANCHI VIA OSTIENSE, 850
VERDI VIA DEL MARE, 8
NERI VIA TORINO, 30
COLOMBO PIAZZA DUOMO, 1
ESPOSITO VIA CARACCIOLO, 100
RUSSO VIA GIULIO CESARE, 119
AMATO VIA NAPOLI, 234
Selezionate 8 righe.
C I
------------------------------ -----------------------------
ROSSI VIA LAURENTINA, 700
BIANCHI VIA OSTIENSE, 850
VERDI VIA DEL MARE, 8
NERI VIA TORINO, 30
COLOMBO PIAZZA DUOMO, 1
ESPOSITO VIA CARACCIOLO, 100
RUSSO VIA GIULIO CESARE, 119
AMATO VIA NAPOLI, 234
Selezionate 8 righe.
138
Alcune volte capita di dover leggere dal database un dato che non
presente in alcuna tabella, ad esempio una stringa di testo fissa, il risultato di
un calcolo aritmetico oppure la data di sistema (SYSDATE). Tali dati
particolari possono essere estratti da qualunque tabella
WTO >select sysdate from clienti;
SYSDATE
---------
02-FEB-11
02-FEB-11
02-FEB-11
02-FEB-11
02-FEB-11
02-FEB-11
02-FEB-11
02-FEB-11
Selezionate 8 righe.
3*5
----------
15
15
15
15
15
15
15
15
Selezionate 8 righe.
'UNASTRINGAFISSA'
-----------------
Una stringa fissa
Una stringa fissa
Una stringa fissa
Una stringa fissa
Una stringa fissa
Una stringa fissa
Una stringa fissa
Una stringa fissa
Selezionate 8 righe.
139
02-FEB-11 15 Una stringa fissa
02-FEB-11 15 Una stringa fissa
Selezionate 8 righe.
NEXTVAL
----------
1
2
3
4
5
6
7
8
Selezionate 8 righe.
140
WTO >select test_seq.currval from clienti;
CURRVAL
----------
8
8
8
8
8
8
8
8
Selezionate 8 righe.
COGNOME ROWID
-------- ------------------
ROSSI AAAlsNAAEAAA7gkAAA
BIANCHI AAAlsNAAEAAA7gkAAB
VERDI AAAlsNAAEAAA7gkAAC
NERI AAAlsNAAEAAA7gkAAD
COLOMBO AAAlsNAAEAAA7gkAAE
ESPOSITO AAAlsNAAEAAA7gkAAF
RUSSO AAAlsNAAEAAA7gkAAG
AMATO AAAlsNAAEAAA7gkAAH
Selezionate 8 righe.
142
BBBBBB il numero del blocco allinterno del datafile
RRR il numero di riga allinterno del blocco.
Nellesempio precedente tutti i record appartengono alloggetto
AAAlsN, tutti si trovano nel blocco AAA7gk del file AAE. Lunica cosa che
cambia di record in record ovviamente la posizione nel blocco: ROSSI il
primo record nel blocco (AAA in base 64 con la codifica definita equivale a
zero in base 10), BIANCHI ha indice uno (AAB) ed quindi il secondo record
e cos via.
Per ogni riga estratta da una query, la pseudocolonna ROWNUM
restituisce un numero che indica l'ordine in cui Oracle seleziona la riga dalla
tabella. La prima riga selezionata ha ROWNUM uguale a 1, la seconda 2 e
cos via.
WTO >select cognome, rownum
2 from clienti;
COGNOME ROWNUM
-------- ----------
ROSSI 1
BIANCHI 2
VERDI 3
NERI 4
COLOMBO 5
ESPOSITO 6
RUSSO 7
AMATO 8
Selezionate 8 righe.
7.4.4 Selezioni
Per estrarre solo una parte delle righe presenti in tabella si utilizza la
clausola WHERE.
SELECT <elenco colonne>
FROM <nome schema>.<nome oggetto>
WHERE <condizione>;
143
Valori fissi
Operatori aritmetici
Operatori logici
Pseudo colonne
La condizione pi semplice assume la forma
<nome colonna> <operatore di confronto> <valore>
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
G811 POMEZIA RM
M297 FIUMICINO RM
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
F205 MILANO MI
G686 PIOLTELLO MI
E415 LAINATE MI
F839 NAPOLI NA
G964 POZZUOLI NA
G902 PORTICI NA
Selezionate 6 righe.
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
F205 MILANO MI
G686 PIOLTELLO MI
E415 LAINATE MI
F839 NAPOLI NA
G964 POZZUOLI NA
G902 PORTICI NA
Selezionate 6 righe.
144
2 where provincia^='RM';
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
F205 MILANO MI
G686 PIOLTELLO MI
E415 LAINATE MI
F839 NAPOLI NA
G964 POZZUOLI NA
G902 PORTICI NA
Selezionate 6 righe.
Selezionate 8 righe.
Tutti gli operatori di confronto visti finora, nonch quelli che saranno
introdotti successivamente, restituiscono il valore UNKNOWN (sconosciuto)
quando sono applicati ad una colonna di valore NULL.
Le condizioni che restituiscono UNKNOWN sono trattate come se
fossero FALSE. Il record non viene estratto.
Questo vuol dire che in presenza di valori NULL non vale la regola
intuitiva che estraendo i record che verificano la condizione:
<nome colonna> = <valore>
145
E quelli che verificano la condizione:
<nome colonna> != <valore>
Selezionate 8 righe.
146
6 GENNARO ESPOSITO SPSGNN71B10F839X VIA CARACCIOLO, 100 80100 F839
7 PASQUALE RUSSO RSSPSQ70C14F839X VIA GIULIO CESARE, 119 80125 F839
La stessa regola vale per tutti gli operatori di confronto che seguono.
Disuguaglianza (>, >=, <, <=)
Lutilizzo molto intuitivo e dunque si procede direttamente con gli
esempi.
WTO >select * from fatture
2 where importo>500;
147
----------- ---------- --------- ---------- -
2 1 01-DIC-10 500 N
4 3 01-FEB-11 1000 N
5 5 01-DIC-10 500 S
Come gi detto, il tipo DATE include sempre anno, mese, giorno, ore,
minuti e secondi. Due date sono uguali quando tutti gli elementi sono uguali,
fino al secondo. Negli esempi precedenti sia le date presenti in tabella che
quelle utilizzate per il confronto hanno ore, minuti e secondi pari alle
00:00:00. Se invece in tabella ci fossero state date comprensive di un orario
differente il comportamento sarebbe cambiato sensibilmente. La data 01-12-
2010 alle 10:00:00 infatti maggiore, non uguale, del valore fisso date'2010-
12-01'. Questultimo rappresenta la mezzanotte del 01-12-2010.
Per osservare questo comportamento cambiamo momentaneamente il
formato di visualizzazione di default delle date con il comando
WTO >ALTER SESSION SET NLS_DATE_FORMAT='dd/mm/yyyy hh24:mi:ss';
Modificata sessione.
148
per aggiungere una settimana DATA+7, per aggiungere solo sei ore
DATA+1/4, essendo sei ore pari ad un quarto di giorno.
WTO >select sysdate, sysdate+1, sysdate+1/4
2 from dual;
Aggiornate 5 righe.
149
1 1 01/10/2010 06:00:00 300 S
3 2 20/10/2010 06:00:00 700 S
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
G811 POMEZIA RM
G686 PIOLTELLO MI
F839 NAPOLI NA
G964 POZZUOLI NA
G902 PORTICI NA
Selezionate 6 righe.
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
G811 POMEZIA RM
F205 MILANO MI
G686 PIOLTELLO MI
F839 NAPOLI NA
G964 POZZUOLI NA
G902 PORTICI NA
Selezionate 7 righe.
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
M297 FIUMICINO RM
E415 LAINATE MI
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
M297 FIUMICINO RM
F205 MILANO MI
E415 LAINATE MI
150
NUM_FATTURA NUM_ORDINE DATA_FATT IMPORTO P
----------- ---------- --------- ---------- -
2 1 01-DIC-10 500 N
3 2 20-OTT-10 700 S
5 5 01-DIC-10 500 S
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
G811 POMEZIA RM
M297 FIUMICINO RM
F205 MILANO MI
G686 PIOLTELLO MI
E415 LAINATE MI
Selezionate 6 righe.
151
Nella lista possono essere specificati fino a mille valori.
Loperatore reciproco della IN NOT IN, esso estrae tutti i record per
cui la colonna indicata non nellelenco.
WTO >select * from comuni
2 where provincia not in ('RM','MI');
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
F839 NAPOLI NA
G964 POZZUOLI NA
G902 PORTICI NA
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
G811 POMEZIA RM
G686 PIOLTELLO MI
G964 POZZUOLI NA
G902 PORTICI NA
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
M297 FIUMICINO RM
F205 MILANO MI
G686 PIOLTELLO MI
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
G686 PIOLTELLO MI
F839 NAPOLI NA
G964 POZZUOLI NA
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
M297 FIUMICINO RM
F205 MILANO MI
E415 LAINATE MI
F839 NAPOLI NA
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
G686 PIOLTELLO MI
G964 POZZUOLI NA
Loperatore reciproco di LIKE NOT LIKE ed estrae tutti i dati che non
rispettano il modello.
WTO >select * from comuni
2 where des_comune not like 'P%';
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
153
H501 ROMA RM
M297 FIUMICINO RM
F205 MILANO MI
E415 LAINATE MI
F839 NAPOLI NA
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
M297 FIUMICINO RM
F205 MILANO MI
G686 PIOLTELLO MI
E415 LAINATE MI
F839 NAPOLI NA
G964 POZZUOLI NA
G902 PORTICI NA
Selezionate 7 righe.
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
G811 POMEZIA RM
E415 LAINATE MI
F839 NAPOLI NA
G964 POZZUOLI NA
G902 PORTICI NA
Selezionate 6 righe.
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
G811 POMEZIA RM
M297 FIUMICINO RM
F205 MILANO MI
E415 LAINATE MI
G902 PORTICI NA
Selezionate 6 righe.
WTO >select * from comuni
2 where des_comune not like '%N%';
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
G811 POMEZIA RM
G686 PIOLTELLO MI
G964 POZZUOLI NA
G902 PORTICI NA
COD_ DES_COMUNE PR
154
---- -------------------------------------------------- --
H501 ROMA RM
G811 POMEZIA RM
M297 FIUMICINO RM
F205 MILANO MI
E415 LAINATE MI
F839 NAPOLI NA
G902 PORTICI NA
Selezionate 7 righe.
Eseguendo la query:
WTO >select * from comuni
2 where des_comune like 'P%';
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
G811 POMEZIA RM
G686 PIOLTELLO MI
G964 POZZUOLI NA
G902 PORTICI NA
Eseguendo la query:
WTO >select * from comuni
2 where provincia = 'NA';
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
F839 NAPOLI NA
G964 POZZUOLI NA
G902 PORTICI NA
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
G964 POZZUOLI NA
G902 PORTICI NA
Disgiunzione (OR)
La disgiunzione di due condizioni consente di estrarre tutti i record
che rispettano o luna o laltra oppure entrambe le condizioni. equivalente
alloperazione insiemistica di UNIONE.
Nellesempio precedente la disgiunzione delle due condizioni estrae
tutti i comuni che si trovano in provincia di Napoli oppure iniziano per P (o
che verificano entrambe le condizioni).
WTO >select * from comuni
2 where provincia = 'NA'
3 or des_comune like 'P%';
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
G811 POMEZIA RM
G686 PIOLTELLO MI
F839 NAPOLI NA
G964 POZZUOLI NA
G902 PORTICI NA
Negazione (NOT)
La negazione di una condizione consente di estrarre tutti i record che
non rispettano la condizione data. equivalente alloperazione insiemistica di
COMPLEMENTO.
Nellesempio precedente possiamo estrarre tutti i comuni che non si
trovano in provincia di Napoli con la condizione
WTO >select * from comuni
2 where not provincia = 'NA';
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
156
G811 POMEZIA RM
M297 FIUMICINO RM
F205 MILANO MI
G686 PIOLTELLO MI
E415 LAINATE MI
Selezionate 6 righe.
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
G811 POMEZIA RM
M297 FIUMICINO RM
F205 MILANO MI
G686 PIOLTELLO MI
E415 LAINATE MI
Selezionate 6 righe.
157
Alla negazione di una congiunzione o di una disgiunzione si applicano
le leggi di De Morgan della teoria degli insiemi.
NOT (<prima condizione> AND <seconda condizione>)
equivalente a
NOT <prima condizione> OR NOT <seconda condizione>
e
NOT (<prima condizione> OR <seconda condizione>)
equivalente a
NOT <prima condizione> AND NOT <seconda condizione>
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
G811 POMEZIA RM
M297 FIUMICINO RM
F205 MILANO MI
G686 PIOLTELLO MI
E415 LAINATE MI
F839 NAPOLI NA
Selezionate 7 righe.
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
G811 POMEZIA RM
M297 FIUMICINO RM
F205 MILANO MI
G686 PIOLTELLO MI
E415 LAINATE MI
F839 NAPOLI NA
Selezionate 7 righe.
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
G811 POMEZIA RM
M297 FIUMICINO RM
F205 MILANO MI
G686 PIOLTELLO MI
E415 LAINATE MI
F839 NAPOLI NA
Selezionate 7 righe.
158
2 where not (provincia = 'NA' or des_comune like 'P%');
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
M297 FIUMICINO RM
F205 MILANO MI
E415 LAINATE MI
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
M297 FIUMICINO RM
F205 MILANO MI
E415 LAINATE MI
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
H501 ROMA RM
M297 FIUMICINO RM
F205 MILANO MI
E415 LAINATE MI
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
G686 PIOLTELLO MI
F839 NAPOLI NA
G964 POZZUOLI NA
G902 PORTICI NA
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
159
G686 PIOLTELLO MI
F839 NAPOLI NA
G964 POZZUOLI NA
G902 PORTICI NA
COD_ DES_COMUNE PR
---- -------------------------------------------------- --
G686 PIOLTELLO MI
G964 POZZUOLI NA
G902 PORTICI NA
7.4.5 Ordinamento
Per ordinare i record estratti da una query necessario aggiungere
una clausola ORDER BY. In assenza di tale clausola Oracle non garantisce
alcun tipo di ordinamento. A prima vista pu sembrare che, in assenza della
clausola ORDER BY, le righe della tabella siano restituite nello stesso ordine
in cui sono state inserite. Non vero.
La forma pi semplice della clausola ORDER BY prevede la seguente
sintassi:
ORDER BY <discriminante>, <discriminante>, ..., <discriminante>
160
WTO >select * from clienti
2 order by nome;
Selezionate 8 righe.
Selezionate 8 righe.
COGNOME INDIRIZZO
-------- ----------------------
COLOMBO PIAZZA DUOMO, 1
NERI VIA TORINO, 30
ESPOSITO VIA CARACCIOLO, 100
RUSSO VIA GIULIO CESARE, 119
VERDI VIA DEL MARE, 8
AMATO VIA NAPOLI, 234
BIANCHI VIA OSTIENSE, 850
ROSSI VIA LAURENTINA, 700
Selezionate 8 righe.
161
3 order by cap+cod_cliente;
COGNOME INDIRIZZO
-------- ----------------------
VERDI VIA DEL MARE, 8
ROSSI VIA LAURENTINA, 700
BIANCHI VIA OSTIENSE, 850
COLOMBO PIAZZA DUOMO, 1
NERI VIA TORINO, 30
AMATO VIA NAPOLI, 234
ESPOSITO VIA CARACCIOLO, 100
RUSSO VIA GIULIO CESARE, 119
Selezionate 8 righe.
N C INDIRIZZO
-------------------------- ----------------------- ----------------------
VINCENZO AMATO VIA NAPOLI, 234
GIOVANNI BIANCHI VIA OSTIENSE, 850
AMBROGIO COLOMBO PIAZZA DUOMO, 1
GENNARO ESPOSITO VIA CARACCIOLO, 100
LUCA NERI VIA TORINO, 30
MARCO ROSSI VIA LAURENTINA, 700
PASQUALE RUSSO VIA GIULIO CESARE, 119
MATTEO VERDI VIA DEL MARE, 8
Selezionate 8 righe.
162
1 MARCO ROSSI RSSMRC70R20H501X VIA LAURENTINA, 700 00143 H501
4 LUCA NERI NRILCU77A22F205X VIA TORINO, 30 20120 F205
6 GENNARO ESPOSITO SPSGNN71B10F839X VIA CARACCIOLO, 100 80100 F839
5 AMBROGIO COLOMBO PIAZZA DUOMO, 1 20100 F205
2 GIOVANNI BIANCHI VIA OSTIENSE, 850 00144 H501
8 VINCENZO AMATO VIA NAPOLI, 234 80022 G964
Selezionate 8 righe.
Selezionate 8 righe.
Selezionate 8 righe.
163
7.4.6 Raggruppamenti
Alcune volte necessario estrarre le righe da una tabella
raggruppandole secondo un determinato criterio.
Ipotizziamo ad esempio di voler conoscere tutti i comuni in cui
residente almeno uno dei nostri clienti, banalmente la prima query che viene
in mente
WTO >select comune from clienti;
COMU
----
H501
H501
G811
F205
F205
F839
F839
G964
Selezionate 8 righe.
COMU
----
F205
F839
G811
G964
H501
DATA_FATT IMPORTO
--------- ----------
01-OTT-10 300
164
20-OTT-10 700
01-DIC-10 500
01-FEB-11 1000
COMU
----
F205
F839
G811
G964
H501
165
Somma un dato numerico presente nelle righe che compongono il
gruppo. Ipotizziamo ad esempio di voler sommare gli importi di tutte le
fatture. Poich ci interessa creare un unico gruppo composto da tutte le
fatture dobbiamo omettere del tutto la clausola GROUP BY:
WTO >select sum(importo) from fatture;
SUM(IMPORTO)
------------
3000
DATA_FATT SUM(IMPORTO)
--------- ------------
01-OTT-10 300
20-OTT-10 700
01-DIC-10 1000
01-FEB-11 1000
SUM(IMPORTO)
------------
300
700
1000
1000
MIN(IMPORTO)
------------
300
NUM_ORDINE MIN(IMPORTO)
---------- ------------
166
1 300
2 700
3 1000
5 500
MAX
Estrae il valore massimo di un dato presente nelle righe che
compongono il gruppo. Si comporta come la MIN.
WTO >select max(importo)
2 from fatture;
MAX(IMPORTO)
------------
1000
NUM_ORDINE MAX(IMPORTO)
---------- ------------
1 500
2 700
3 1000
5 500
AVG
Calcola il valore medio di un dato presente nelle righe che
compongono il gruppo.
WTO >select avg(importo)
2 from fatture;
AVG(IMPORTO)
------------
600
NUM_ORDINE AVG(IMPORTO)
---------- ------------
1 400
2 700
3 1000
5 500
VARIANCE
Calcola la varianza di un dato presente nelle righe che compongono il
gruppo.
WTO >select variance(importo)
2 from fatture;
VARIANCE(IMPORTO)
-----------------
70000
167
WTO >select num_ordine, variance(importo)
2 from fatture
3 group by num_ordine;
NUM_ORDINE VARIANCE(IMPORTO)
---------- -----------------
1 20000
2 0
3 0
5 0
STDDEV
Calcola la deviazione standard di un dato presente nelle righe che
compongono il gruppo
STDDEV(IMPORTO)
---------------
264,575131
NUM_ORDINE STDDEV(IMPORTO)
---------- ---------------
1 141,421356
2 0
3 0
5 0
COUNT
Conta le righe presenti nel gruppo. lunica funzione di gruppo che
pu prendere in input un singolo dato oppure il carattere jolly *.
Se la funzione COUNT riceve in input un dato conta solo le righe che
hanno quel dato valorizzato, non NULL. Se invece riceve in input * conta
tutte le righe presenti nel gruppo a prescindere dal fatto che i valori siano
NULL oppure no.
Per contare tutte le righe presenti in una tabella si utilizza dunque la
sintassi
SELECT COUNT(*) FROM <nome tabella>
COUNT(*)
----------
8
168
COUNT(NOME)
-----------
8
COUNT(COD_FISC)
---------------
5
NUM_ORDINE COUNT(*)
---------- ----------
1 2
2 1
3 1
5 1
Si ottiene un errore. Una volta che il risultato della query stato diviso
in gruppi per comune necessario, per ogni gruppo, estrarre un valore del
nome. Ci ovviamente non possibile perch in ogni gruppo ci possono
essere nomi differenti ed Oracle non saprebbe quale estrarre.
In una query in cui presente la clausola GROUP BY Oracle segue il
seguente flusso. Innanzi tutto applica la clausola WHERE e scarta le righe
che non la rispettano.
Successivamente raggruppa le righe rispetto alle colonne indicate
nella clausola GROUP BY e calcola le funzioni di gruppo. In questo modo
ottiene le righe accorpate.
A questo punto potrebbe essere necessario escludere alcune righe
accorpate. Ci non pu essere fatto con la clausola WHERE poich, come
detto, questa viene applicata prima del raggruppamento.
169
Per questa esigenza esiste la clausola HAVING. Questa clausola
accetta una condizione che viene applicata alle righe accorpate al fine di
escludere quelle che non la verificano.
Ipotizziamo ad esempio di voler estrarre le fatture accorpate per
numero ordine escludendo gli ordini che hanno meno di due fatture.
Innanzi tutto necessario utilizzare una clausola GROUP BY per
numero ordine, successivamente bisogna escludere con una HAVING le
righe che hanno COUNT(*) minore di due.
WTO >select num_ordine, sum(importo), count(*)
2 from fatture
3 group by num_ordine
4 having count(*)>=2;
Lordine numero 1 arriva ad 800 euro con due fatture mentre lordine
numero 3 arriva a 1000 euro con una sola fattura.
La condizione della HAVING pu essere composta con gli operatori
logici e gli operatori di confronto esattamente come la condizione utilizzata
nella clausola WHERE. Ad esempio potremmo estratte tutti gli ordini che
hanno almeno due fatture oppure una sola fattura di importo almeno 700
euro col comando:
WTO >select num_ordine, sum(importo), count(*)
2 from fatture
3 group by num_ordine
4 having count(*)>=2
5 or (count(*)=1 and sum(importo) >=700);
Selezionate 9 righe.
Selezionate 12 righe.
invece di
JOB
Selezionate 12 righe.
Dove
nvl(job,' Tot. '||deptno)
Selezionate 13 righe.
Selezionate 13 righe.
COGNOME ROWNUM
-------- ----------
ROSSI 1
BIANCHI 2
VERDI 3
NERI 4
COLOMBO 5
ESPOSITO 6
RUSSO 7
AMATO 8
173
Selezionate 8 righe.
COGNOME ROWNUM
-------- ----------
ROSSI 1
BIANCHI 2
VERDI 3
COGNOME ROWNUM
-------- ----------
BIANCHI 2
ROSSI 1
VERDI 3
174
Per definizione il primo record estratto ha ROWNUM=1, esso dunque
non verifica la condizione e viene scartato. Tocca al secondo record che
assume anch'esso ROWNUM=1 (visto che il precedente stato scartato) e
dunque anch'esso viene scartato. Cos via per tutti i restanti record.
Hanno invece senso le seguenti:
WTO >select cognome, rownum
2 from clienti
3 where rownum=1;
COGNOME ROWNUM
-------- ----------
ROSSI 1
COGNOME ROWNUM
-------- ----------
ROSSI 1
BIANCHI 2
VERDI 3
COGNOME ROWNUM
-------- ----------
ROSSI 1
BIANCHI 2
VERDI 3
NERI 4
175
quarta lo stipendio dei dipendenti del dipartimento 30. Fino ad Oracle 10g
avremmo risolto con una UNION:
SQL> select ename, sal d10, null d20, null d30
2 from emp where deptno=10
3 union
4 select ename, null d10, sal d20, null d30
5 from emp where deptno=20
6 union
7 select ename, null d10, null d20, sal d30
8 from emp where deptno=30;
176
La somma degli stipendi per dipartimento (con i risultati in colonne
distinte):
SQL> select sum(d10),sum(d20),sum(d30) from emp
2 pivot (sum(sal) for deptno
3 in (10 as D10, 20 as d20, 30 as d30));
e di voler ottenere nove record, uno per ogni dipartimento e per ogni
anno.
WTO> select *
2 from vendite
3 UNPIVOT
4 (importo for anno in (
5 anno_2008 as '2008',
6 anno_2009 as '2009',
7 anno_2010 as '2010')
8 );
177
30 2010 600000
9 rows selected.
1 row updated.
8 rows selected.
178
10 2009 400000
10 2010 500000
20 2008 185000
20 2009 220000
20 2010
30 2008 400000
30 2009 500000
30 2010 600000
9 rows selected.
179
2 from emp;
180
Non necessario che ci sia un'unica radice dell'albero.
La pseudo colonna LEVEL indica a che livello si trova ogni record nella
gerarchia, partendo dal presupposto che le radici dell'albero hanno
LEVEL=1.
Detto questo possiamo leggere il nostro albero nel risultato della query
appena eseguita: KING padre di tutti ed ha livello 1.
Sotto di lui ci sono tre dipendenti a livello 2 (JONES,BLAKE e CLARK).
Di seguito tutti gli altri.
Come viene realizzata la gerarchia? Prima di tutto si leggono i record.
Poi si determinano le radici applicando la clausola START WITH.
Successivamente a partire da ogni radice si determinano i figli di primo livello
applicando la CONNECT BY e cos via per ogni figlio.
Per migliorare un po' la visualizzazione dell'output possiamo ricorrere
allutilizzo della LPAD:
WTO> select empno,lpad(' ',level*3,' ')||ename nome,
2 mgr, prior ename, level
3 from emp
4 connect by prior empno = mgr
5 start with mgr is null;
Abbiamo aggiunto un po' di spazi alla sinistra del nome in funzione del
livello. Adesso la visualizzazione decisamente migliore.
Come si vede l'ordinamento dei record definisce anche la gerarchia,
aggiungendo una clausola ORDER BY perderemmo completamente la
visione della gerarchia. C' per la possibilit di decidere con che criterio
ordinare pi record che si trovano allo stesso livello (fratelli), come ad
esempio JONES, BLAKE e CLARK:
WTO> select empno,lpad(' ',level*3,' ')||ename nome,
2 mgr, prior ename, level
3 from emp
4 connect by prior empno = mgr
5 start with mgr is null
6 order siblings by ename;
181
---------- ------------------ ---------- ---------- ----------
7839 KING 1
7698 BLAKE 7839 KING 2
7499 ALLEN 7698 BLAKE 3
7900 JAMES 7698 BLAKE 3
7654 MARTIN 7698 BLAKE 3
7844 TURNER 7698 BLAKE 3
7521 WARD 7698 BLAKE 3
7782 CLARK 7839 KING 2
7934 MILLER 7782 CLARK 3
7566 JONES 7839 KING 2
7902 FORD 7566 JONES 3
7369 SMITH 7902 FORD 4
7788 SCOTT 7566 JONES 3
7876 ADAMS 7788 SCOTT 4
Abbiamo detto che KING figlio di SMITH, che per a sua volta
pronipote di KING. Che succede, dunque, se rieseguiamo la query
precedente?
WTO> select empno,lpad(' ',level*3,' ')||ename nome,
2 mgr, prior ename, level
3 from emp
4 connect by prior empno = mgr
5 start with mgr is null
6 order siblings by ename;
Certo, perch non c' nessun record con MGR NULL. Allora
cambiamo la START WITH come segue:
WTO> select empno,lpad(' ',level*3,' ')||ename nome,
2 mgr, prior ename, level
3 from emp
4 connect by prior empno = mgr
5 start with empno=7839;
ERROR:
ORA-01436: CONNECT BY in loop sui dati utente
182
---------- ------------------ ---------- ---------- ----------
7839 KING 7369 1
7566 JONES 7839 KING 2
7788 SCOTT 7566 JONES 3
7876 ADAMS 7788 SCOTT 4
7902 FORD 7566 JONES 3
7369 SMITH 7902 FORD 4
7698 BLAKE 7839 KING 2
7499 ALLEN 7698 BLAKE 3
7521 WARD 7698 BLAKE 3
7654 MARTIN 7698 BLAKE 3
7844 TURNER 7698 BLAKE 3
7900 JAMES 7698 BLAKE 3
7782 CLARK 7839 KING 2
7934 MILLER 7782 CLARK 3
Selezionate 14 righe.
183
EMPNO NOME BOSS
---------- ------------------ ----------
7839 KING KING
7566 JONES KING
7788 SCOTT KING
7876 ADAMS KING
7902 FORD KING
7369 SMITH KING
7698 BLAKE KING
7499 ALLEN KING
7521 WARD KING
7654 MARTIN KING
7844 TURNER KING
7900 JAMES KING
7782 CLARK KING
7934 MILLER KING
Selezionate 14 righe.
Nel nostro caso c' una sola radice, KING, ma se modifichiamo un po'
i dati:
WTO> update emp set mgr=null where ename='BLAKE';
Aggiornata 1 riga.
184
5* start with mgr is null
LEVEL
----------
1
2
3
4
5
6
7
185
Selezionate 7 righe.
Possiamo estrarre da DUAL, che come tutti sanno ha una sola riga,
tutti i record che ci servono per fare elaborazioni complesse.
Vediamo due esempi pratici.
Il primo esempio riguarda laggregazione di stringhe.
SELECT deptno, ltrim(SYS_CONNECT_BY_PATH(ename, ','),',') enames
FROM (select deptno, ename, rank()
over(partition by deptno order by rownum) num from emp)
where connect_by_isleaf=1
START WITH num=1
CONNECT BY PRIOR num+1 = num and prior deptno=deptno;
DEPTNO ENAMES
---------- ----------------------------------------
10 CLARK,KING,MILLER
20 SMITH,JONES,SCOTT,ADAMS,FORD
30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES
STR
-------------------------
prae
epar
arpe
rpae
paer
pare
repa
reap
prea
earp
aepr
aerp
pera
erpa
arep
erap
aper
pear
epra
eapr
186
rpea
rape
raep
apre
Selezionate 24 righe.
C NAME COD
- ---- ----------
p pera 1112
e pera 2101
r pera 3114
a pera 4097
Tabella creata.
X
----------
1
2
3
4
5
6
7
8
187
9
10
11
12
13
14
15
16
17
18
19
20
20 righe selezionate.
X
----------
11
12
13
14
15
16
17
18
19
20
10 righe selezionate.
X
----------
1
2
3
4
5
6
7
8
9
10
188
10 righe selezionate.
X
----------
1
2
3
4
5
6
7
8
8 righe selezionate.
X
----------
1
X
----------
1
X
----------
1
2
3
4
5
6
7
8
9
10
10 righe selezionate.
X
----------
1
2
3
189
4
5
6
7
8
8 righe selezionate.
20 righe create.
X
----------
1
1
2
2
3
X
----------
1
1
2
2
3
3
6 righe selezionate.
X
----------
1
1
190
2
2
3
Pagina 2, da 5 righe
O12c>Select * from test_fetch
2 order by x
3 OFFSET 5 ROWS
4 FETCH FIRST 5 ROWS ONLY;
X
----------
3
4
4
5
5
Pagina N, da 15 righe
O12c>Select * from test_fetch
2 order by x
3 OFFSET 5*(&N-1) ROWS
4 FETCH FIRST 5 ROWS ONLY;
Immettere un valore per n: 3
vecchio 3: OFFSET 5*(&N-1) ROWS
nuovo 3: OFFSET 5*(3-1) ROWS
X
----------
6
6
7
7
8
Tabella creata.
O12c>desc andamento
Nome Nullo? Tipo
------------------------------------ -------- ---------------
SQUADRA VARCHAR2(10)
GIORNATA NUMBER(2)
PUNTI NUMBER(1)
192
insert into andamento values ('NAPOLI',13,3);
insert into andamento values ('NAPOLI',14,3);
insert into andamento values ('NAPOLI',15,3);
insert into andamento values ('NAPOLI',16,3);
insert into andamento values ('NAPOLI',17,1);
insert into andamento values ('NAPOLI',18,1);
insert into andamento values ('NAPOLI',19,3);
38 righe selezionate.
8 righe selezionate.
194
10 peggio as peggio.punti <= prev(peggio.punti)
11 and peggio.punti<3,
12 meglio as meglio.punti > prev(meglio.punti)
13 and prev(meglio.punti)<3
La Juve ha avuto una difficolt alla quarta giornata, poi tre turni difficili
tra la settima e la non giornata (con momento peggiore, una sconfitta,
allottava) e cos via
Indovinate per chi faccio il tifo:
O12c>select squadra, sum(punti)
2 from andamento
3 group by squadra
4 order by sum(punti) desc;
SQUADRA SUM(PUNTI)
---------- ----------
NAPOLI 41
JUVE 35
195
Oracle lavora continuamente per aumentare la capacit di calcolo
complesso delle query. In quest'ottica, a partire dalla versione 10g del DB,
stata aggiunta la clausola MODEL al comando di query.
Questa clausola consente di trattare i dati estratti da una query come
un foglio di calcolo. Consente inoltre di referenziare le singole celle per
alterarne il valore oppure per utilizzarle come base di calcolo per altre celle.
Per gli esempi che seguono stata utilizzata la tabella
BILANCIO_FAMILIARE, di cui segue lo script di creazione e popolamento:
196
30-DEC-09 D AUTO PIENO 60
10-JAN-10 D AUTO PIENO 60
20-JAN-10 D AUTO PIENO 60
30-JAN-10 D AUTO PIENO 60
01-JAN-10 D CASA RATA MUTUO 510
15-DEC-09 A STIPENDI 13esima 2000
27-DEC-09 A STIPENDI Dicembre 2200
27-JAN-10 A STIPENDI Gennaio 2400
15-DEC-09 D REGALI Natale 800
25-DEC-09 A REGALI Natale 200
14 rows selected.
Selezionate 9 righe.
198
2010 D AUTO 180
2010 D CASA 510
2010 D TOTALE CASA e AUTO 690
13 rows selected.
Come si vede, nella clausola MODEL sono state prima di tutto definite
PARTIZIONI, DIMENSIONI e MISURE.
Poi si passati alle regole, indicando che l'importo in Dare con
categoria TOTALE CASA E AUTO dato dalla somma degli importi Dare
aventi categorie CASA e AUTO.
Con la stessa logica stato calcolato il TOTALE AVERE.
Notiamo per che il TOTALE AVERE del 2010 ha importo nullo perch
per il 2010 manca la cella (A, REGALI). Come al solito sommando quindi
questo valore NULL al valore della cella (A, STIPENDI) si ottiene NULL.
Per ovviare al problema si pu banalmente utilizzare la funzione NVL:
WTO> select anno, segno, categoria, importo
2 from (select to_char(data,'yyyy') anno, segno,
3 categoria, sum(importo) importo
4 from bilancio_familiare
5 group by to_char(data,'yyyy'), segno, categoria)
6 model
7 PARTITION BY (anno) DIMENSION BY (segno, categoria)
8 MEASURES (importo)
9 RULES
10 (importo['D', 'TOTALE CASA e AUTO'] =
11 importo['D', 'CASA'] + importo['D', 'AUTO'],
12 importo['A', 'TOTALE AVERE'] =
13 nvl(importo['A', 'STIPENDI'],0) +
14 nvl(importo['A', 'REGALI'],0)
15 )
16 ORDER BY anno, segno,categoria;
13 rows selected.
199
2 from (select to_char(data,'yyyy') anno, segno,
3 categoria, sum(importo) importo
4 from bilancio_familiare
5 group by to_char(data,'yyyy'), segno, categoria)
6 model
7 PARTITION BY (anno) DIMENSION BY (segno, categoria)
8 MEASURES (importo)
9 RULES
10 (importo['D', 'TOTALE CASA e AUTO'] =
11 importo['D', 'CASA'] + importo['D', 'AUTO'],
12 importo['A', 'TOTALE AVERE'] =
13 nvl(importo['A', 'STIPENDI'],0)
14 + nvl(importo['A', 'REGALI'],0),
15 importo['D', 'TOTALE DARE'] =
16 sum(importo)['D',categoria like '%']
17 )
18 ORDER BY anno, segno,categoria;
15 rows selected.
200
Aggiorna le celle gi presenti ed aggiunge nuove celle su un numero
pi ampio di regole
Si pu specificare una modalit di calcolo per ogni regola ed il default
UPSERT.
Vediamo un esempio.
Tutte le celle che abbiamo calcolato finora sono celle aggiunte,
essendo totali. Poich non abbiamo mai specificato la modalit di calcolo
essa vale UPSERT e le celle sono sempre state create.
Utilizziamo invece la modalit UPDATE per il calcolo del TOTALE
DARE.
WTO> select anno, segno, categoria, importo
2 from (select to_char(data,'yyyy') anno, segno,
3 categoria, sum(importo) importo
4 from bilancio_familiare
5 group by to_char(data,'yyyy'), segno, categoria)
6 model
7 PARTITION BY (anno) DIMENSION BY (segno, categoria)
8 MEASURES (importo)
9 RULES
10 (importo['D', 'TOTALE CASA e AUTO'] =
11 importo['D', 'CASA'] + importo['D', 'AUTO'],
12 importo['A', 'TOTALE AVERE'] =
13 nvl(importo['A', 'STIPENDI'],0)
14 + nvl(importo['A', 'REGALI'],0),
15 UPDATE importo['D', 'TOTALE DARE'] =
16 sum(importo)['D',categoria like '%']
17 )
18 ORDER BY anno, segno,categoria;
13 rows selected.
Rispetto a prima abbiamo perso due righe. I due totali dare per il 2009
ed il 2010.
Siccome la cella (D, TOTALE DARE) non esiste al momento
dell'estrazione, la regola in modalit UPDATE non l'aggiunge.
Se invece proviamo ad inserire in tabella un record fatto cos:
insert into bilancio_familiare values
(DATE '2009-12-25', 'D', 'TOTALE DARE', null,1000);
201
La situazione cambia perch adesso la cella (D, TOTALE DARE) per il
2009 presente e dunque la regola pu essere applicata in modalit
UPDATE:
WTO> select anno, segno, categoria, importo
2 from (select to_char(data,'yyyy') anno, segno,
3 categoria, sum(importo) importo
4 from bilancio_familiare
5 group by to_char(data,'yyyy'), segno, categoria)
6 model
7 PARTITION BY (anno) DIMENSION BY (segno, categoria)
8 MEASURES (importo)
9 RULES
10 (importo['D', 'TOTALE CASA e AUTO'] =
11 importo['D', 'CASA'] + importo['D', 'AUTO'],
12 importo['A', 'TOTALE AVERE'] =
13 nvl(importo['A', 'STIPENDI'],0)
14 + nvl(importo['A', 'REGALI'],0),
15 UPDATE importo['D', 'TOTALE DARE'] =
16 sum(importo)['D',categoria like '%']
17 )
18 ORDER BY anno, segno,categoria;
14 rows selected.
202
12 ORDER BY anno, segno,categoria;
Selezionate 9 righe.
Selezionate 11 righe.
203
6 model
7 PARTITION BY (anno) DIMENSION BY (segno, categoria)
8 MEASURES (importo)
9 RULES
10 (importo['D', 'TOTALE CASA e AUTO'] =
11 importo['D', 'CASA'] + importo['D', 'AUTO'],
12 importo['A', 'TOTALE AVERE'] =
13 nvl(importo['A', 'STIPENDI'],0)
.14 + nvl(importo['A', 'REGALI'],0),
15 UPDATE importo['D', 'TOTALE DARE'] =
16 sum(importo)['D',ANY]
17 )
18 ORDER BY anno, segno,categoria;
14 rows selected.
204
2009 A STIPENDI 4200
2009 A TOTALE AVERE 4400
2009 D AUTO 180
2009 D CASA 500
2009 D PERSONALI 1000
2009 D REGALI 800
2009 D TOTALE DARE 3480
2010 A STIPENDI 2400
2010 A TOTALE AVERE 2400
2010 D AUTO 180
2010 D CASA 510
2010 D TOTALE DARE 690
13 rows selected.
Selezionate 13 righe.
205
A destra per abbiamo bisogno di indicare "La somma di tutti gli
importi che hanno come segno QUELLO CHE STO LAVORANDO A
SINISTRA".
La funzione CV fa proprio questo. Consente di mettere a destra
dell'espressione di una regola un riferimento al valore corrente della
dimensione che attualmente in fase di lavorazione.
Le potenzialit di MODEL si spingono ancora oltre. In particolare
degna di nota segnalare la capacit definire dei cicli iterativi da applicare per
il calcolo delle celle. Per tutti gli approfondimenti del caso si rimanda alla
documentazione ufficiale.
NOME||COGNOME
--------------------------------------------
MARCOROSSI
GIOVANNIBIANCHI
MATTEOVERDI
LUCANERI
AMBROGIOCOLOMBO
GENNAROESPOSITO
PASQUALERUSSO
VINCENZOAMATO
Selezionate 8 righe.
NOME||''||COGNOME
-----------------------------------------------
MARCO ROSSI
GIOVANNI BIANCHI
MATTEO VERDI
LUCA NERI
AMBROGIO COLOMBO
GENNARO ESPOSITO
PASQUALE RUSSO
206
VINCENZO AMATO
Selezionate 8 righe.
NOME||''||COD_FISC
------------------------------------
MARCO RSSMRC70R20H501X
GIOVANNI
MATTEO VRDMTT69S02H501X
LUCA NRILCU77A22F205X
AMBROGIO
GENNARO SPSGNN71B10F839X
PASQUALE RSSPSQ70C14F839X
VINCENZO
Selezionate 8 righe.
DATA_FATTURA||'-'||IMPORTO
---------------------------------------------
01-OTT-10-300
01-DIC-10-500
20-OTT-10-700
01-FEB-11-1000
01-DIC-10-500
3+5
----------
8
Sottrazione ()
WTO >select importo, importo-100
2 from fatture;
IMPORTO IMPORTO-100
---------- -----------
300 200
500 400
700 600
1000 900
500 400
Moltiplicazione (*)
WTO >select importo, importo*0.20 iva
207
2 from fatture;
IMPORTO IVA
---------- ----------
300 60
500 100
700 140
1000 200
500 100
Divisione (/)
WTO >select importo, importo/2
2 from fatture;
IMPORTO IMPORTO/2
---------- ----------
300 150
500 250
700 350
1000 500
500 250
3*(5-2)/4+1
-----------
3,25
3*5-2/4+1
----------
15,5
CONCAT(NOME,COGNOME)
------------------------------------------------------------
MARCOROSSI
GIOVANNIBIANCHI
MATTEOVERDI
LUCANERI
AMBROGIOCOLOMBO
GENNAROESPOSITO
PASQUALERUSSO
VINCENZOAMATO
Selezionate 8 righe.
CONCAT(NOME,CONCAT('',COGNOME))
-------------------------------------------------------------
MARCO ROSSI
GIOVANNI BIANCHI
MATTEO VERDI
LUCA NERI
AMBROGIO COLOMBO
GENNARO ESPOSITO
PASQUALE RUSSO
VINCENZO AMATO
Selezionate 8 righe.
SUBSTR
La funzione SUBSTR estrae una sottostringa da una stringa data. La
funzione riceve in input tre parametri: la stringa di partenza; la posizione,
allinterno della stringa di partenza, a partire dalla quale bisogna estrarre i
caratteri; la lunghezza della stringa da estrarre.
Ipotizziamo ad esempio di voler estrarre i primi tre caratteri del nome
dei clienti. La posizione di partenza uno, la lunghezza della stringa tre.
WTO >select nome, substr(nome,1,3) from clienti;
NOME SUB
-------- ---
MARCO MAR
GIOVANNI GIO
MATTEO MAT
LUCA LUC
AMBROGIO AMB
GENNARO GEN
PASQUALE PAS
VINCENZO VIN
NOME SUB
-------- ---
MARCO RCO
GIOVANNI OVA
MATTEO TTE
LUCA CA
AMBROGIO BRO
GENNARO NNA
PASQUALE SQU
209
VINCENZO NCE
NOME SUB
-------- ---
MARCO RCO
GIOVANNI NNI
MATTEO TEO
LUCA UCA
AMBROGIO GIO
GENNARO ARO
PASQUALE ALE
VINCENZO NZO
Selezionate 8 righe.
NOME S
-------- -
MARCO
GIOVANNI
MATTEO
LUCA
AMBROGIO
GENNARO
PASQUALE
VINCENZO
Selezionate 8 righe.
NOME SUBSTR(NOME,3)
-------- ----------------------------
MARCO RCO
GIOVANNI OVANNI
MATTEO TTEO
LUCA CA
AMBROGIO BROGIO
GENNARO NNARO
PASQUALE SQUALE
VINCENZO NCENZO
Selezionate 8 righe.
NOME SUB
210
-------- ---
MARCO RCO
GIOVANNI NNI
MATTEO TEO
LUCA UCA
AMBROGIO GIO
GENNARO ARO
PASQUALE ALE
VINCENZO NZO
Selezionate 8 righe.
NOME INSTR(NOME,'A')
-------- ---------------
MARCO 2
GIOVANNI 5
MATTEO 2
LUCA 4
AMBROGIO 1
GENNARO 5
PASQUALE 2
VINCENZO 0
NOME INSTR(NOME,'AR')
-------- ----------------
MARCO 2
GIOVANNI 0
MATTEO 0
LUCA 0
AMBROGIO 0
GENNARO 5
PASQUALE 0
VINCENZO 0
NOME INSTR(NOME,'A',3)
-------- -----------------
MARCO 0
GIOVANNI 5
MATTEO 0
LUCA 4
AMBROGIO 0
GENNARO 5
PASQUALE 6
VINCENZO 0
Selezionate 8 righe.
NOME INSTR(NOME,'A',1,2)
-------- -------------------
MARCO 0
GIOVANNI 0
MATTEO 0
LUCA 0
AMBROGIO 0
GENNARO 0
PASQUALE 6
VINCENZO 0
Selezionate 8 righe.
NOME LENGTH(NOME)
-------- ------------
MARCO 5
GIOVANNI 8
MATTEO 6
LUCA 4
AMBROGIO 8
GENNARO 7
PASQUALE 8
VINCENZO 8
Selezionate 8 righe.
212
WTO >select cod_fisc, length(cod_fisc) from clienti;
COD_FISC LENGTH(COD_FISC)
---------------- ----------------
RSSMRC70R20H501X 16
VRDMTT69S02H501X 16
NRILCU77A22F205X 16
SPSGNN71B10F839X 16
RSSPSQ70C14F839X 16
Selezionate 8 righe.
LOWER(NOME)
------------------------------
marco
giovanni
matteo
luca
ambrogio
gennaro
pasquale
vincenzo
Selezionate 8 righe.
UPPER('UNASTRINGAMINU
---------------------
UNA STRINGA MINUSCOLA
INITCAP(NOME)
------------------------------
Marco
Giovanni
Matteo
Luca
Ambrogio
Gennaro
Pasquale
Vincenzo
213
INITCAP('UNASTRINGAMI
---------------------
Una Stringa Minuscola
LTRIM('XXX
----------
STRINGAXXX
LTRIM('XYX
----------
STRINGAXXX
LTRIM('STRI
-----------
STRINGA
LTRIM('STRI
-----------
STRINGA
RTRIM('XXX
----------
XXXSTRINGA
RTRIM('XYXYX
------------
XYXYXSTRINGA
RTRIM('STRIN
------------
STRINGA
214
RTRIM('STRIN
------------
STRINGA
La funzione TRIM elimina gli spazi sia dalla destra che dalla sinistra di
una stringa:
WTO >select trim(' STRINGA ') from dual;
TRIM('S
-------
STRINGA
LTRIM(R
-------
STRINGA
LPAD ed RPAD
La funzione LPAD riceve in input due stringhe ed una lunghezza.
Effettua il riempimento della prima stringa con la seconda stringa fino a
raggiungere la lunghezza data. Ipotizziamo ad esempio di voler riempire a
sinistra i nomi dei clienti con caratteri asterisco fino ad una lunghezza di dieci
caratteri.
WTO >select lpad(nome,10,'*') from clienti;
LPAD(NOME,
----------
*****MARCO
**GIOVANNI
****MATTEO
******LUCA
**AMBROGIO
***GENNARO
**PASQUALE
**VINCENZO
Selezionate 8 righe.
LPAD(NO
-------
**MARCO
GIOVANN
*MATTEO
***LUCA
AMBROGI
GENNARO
PASQUAL
VINCENZ
Selezionate 8 righe.
RPAD(NOME,
----------
MARCO*****
GIOVANNI**
MATTEO****
LUCA******
AMBROGIO**
GENNARO***
PASQUALE**
VINCENZO**
RPAD(NO
-------
MARCO**
GIOVANN
MATTEO*
LUCA***
AMBROGI
GENNARO
PASQUAL
VINCENZ
Selezionate 8 righe.
REPLACE
La funzione REPLACE riceve in input tre stringhe ed effettua una
sostituzione, nella prima stringa tutte le occorrenze della seconda stringa
vengono sostituite con occorrenze della terza. Ad esempio se nel nome dei
clienti si intende sostituire le lettere A con il carattere asterisco si scriver.
WTO >select replace(nome,'A','*') from clienti;
REPLACE(NOME,'A','*')
------------------------------
M*RCO
GIOV*NNI
M*TTEO
LUC*
*MBROGIO
216
GENN*RO
P*SQU*LE
VINCENZO
Selezionate 8 righe.
REPLACE(NOME,'A','<+>')
----------------------------------------------------------
M<+>RCO
GIOV<+>NNI
M<+>TTEO
LUC<+>
<+>MBROGIO
GENN<+>RO
P<+>SQU<+>LE
VINCENZO
Selezionate 8 righe.
TRANSLATE
La funzione TRANSLATE riceve in input tre stringhe ed effettua una
sostituzione. La prima stringa quella in cui viene effettuata la sostituzione.
La seconda e la terza stringa rappresentano due alfabeti. Ogni occorrenza
del carattere che si trova al primo posto nel primo alfabeto sar sostituito con
unoccorrenza del carattere che si trova al primo posto nel secondo alfabeto
e cos via. Ad esempio, nei nomi dei clienti, vogliamo sostituire ogni A con
un *, ogni M con un - ed ogni R con un +. Scriveremo.
WTO >select nome, translate(nome,'AMR','*-+') from clienti;
NOME TRANSLATE(NOME,'AMR','*-+')
-------- ------------------------------
MARCO -*+CO
GIOVANNI GIOV*NNI
MATTEO -*TTEO
LUCA LUC*
AMBROGIO *-B+OGIO
GENNARO GENN*+O
PASQUALE P*SQU*LE
VINCENZO VINCENZO
Selezionate 8 righe.
217
3 from dual;
TRANSLATE('STRINGA*+-:CON.:/\C
------------------------------
stringa con caratteri speciali
ASCII e CHR
La funzione ASCII riceve in input un carattere e ne restituisce il codice
ASCII ( 10.4.3) nel set di caratteri del database.
WTO >select ascii('A') from dual;
ASCII('A')
----------
65
ASCII('A')
----------
97
ASCII('{')
----------
123
C C C
- - -
A a {
ABS
La funzione ABS riceve in input un numero e ne restituisce il valore
assoluto.
WTO >select abs(-3), abs(5) from dual;
ABS(-3) ABS(5)
---------- ----------
3 5
ROUND e TRUNC
La funzione ROUND riceve in input un numero e lo restituisce
arrotondato alla parte intera. Larrotondamento aritmetico prevede che le
cifre non significative (i decimali in questo caso) vengano abbandonate,
lultima cifra significativa viene aumentata di una unit se la prima cifra non
significativa va da cinque a nove.
218
WTO >select round(10.3), round(3.5), round(2.4)
2 from dual;
219
2 from dual;
CEIL e FLOOR
La funzione CEIL restituisce il pi piccolo intero maggiore o uguale del
numero ricevuto in input.
WTO >select ceil(2.6), ceil(3), ceil(3.3)
2 from dual;
EXP, LN e LOG
La funzione esponenziale EXP restituisce il risultato di una potenza
avente come base il numero di Nepero (detto anche numero di Eulero
2,718281828459) e come esponente il numero passato in input alla
funzione.
220
WTO >select exp(1), exp(2)
2 from dual;
EXP(1) EXP(2)
------------ ------------
2,7182818285 7,3890560989
LN(2.7182818285) LN(10)
---------------- ------------
1 2,302585093
LOG(10,10) LOG(2,8)
------------ ------------
1 3
POWER e SQRT
La funzione potenza POWER riceve in input due numeri. Restituisce il
risultato di una potenza avente come base il primo parametro e come
esponente il secondo.
WTO >select power(2,3), power(10,4)
2 from dual;
POWER(2,3) POWER(10,4)
------------ ------------
8 10000
SQRT(16) SQRT(2)
------------ ------------
4 1,4142135624
SIGN
La funzione segno SIGN riceve in input un numero e restituisce:
1 se il numero in input maggiore di zero,
0 se il numero in input zero,
-1 se il numero in input minore di zero.
WTO >select sign(-23), sign(0), sign(3)
2 from dual;
221
-1 0 1
MOD e REMAINDER
La funzione modulo MOD riceve in input due numeri e restituisce il
resto che si ottiene dividendo il primo parametro per il secondo.
WTO >select mod(10,3), mod(28,7), mod(17,9)
2 from dual;
MOD(10,7) REMAINDER(10,7)
---------- ---------------
3 3
MOD(10,6) REMAINDER(10,6)
---------- ---------------
4 -2
TRIGONOMETRICHE
Oracle mette a disposizione alcune funzioni trigonometriche che ci
limiteremo ad elencare: seno (SIN) e seno iperbolico (SINH); coseno (COS)
e coseno iperbolico (COSH); tangente (TAN) e tangente iperbolica (TANH);
arcoseno (ASIN), arco coseno (ACOS), arcotangente (ATAN) ed
arcotangente a due parametri (ATAN2). Le due funzioni arcotangente sono
legate dalla seguente equivalenza:
ATAN2(a,b) = ATAN(a/b).
222
In questo modo per tutte le date saranno visualizzati: due cifre per il
giorno, due cifre per il mese, quattro cifre per lanno, due cifre per lora nel
formato a 24 ore, due cifre per i minuti e due cifre per i secondi.
SYSDATE e SYSTIMESTAMP
La funzione SYSDATE, senza parametri, restituisce la data corrente.
WTO >select sysdate from dual;
SYSDATE
-------------------
13-02-2011 17:39:11
ADD_MONTHS(DATE'201
-------------------
223
13-10-2010 00:00:00
ADD_MONTHS(DATE'201
-------------------
31-03-2011 00:00:00
ADD_MONTHS(DATE'201
-------------------
30-04-2011 00:00:00
ADD_MONTHS(DATE'201
-------------------
31-01-2011 00:00:00
ADD_MONTHS(DATE'201
-------------------
31-12-2010 00:00:00
MONTHS_BETWEEN
La funzione MONTHS_BETWEEN prende in input due date e ritorna la
differenza in mesi tra le due. Il risultato positivo se la prima data
maggiore della seconda, altrimenti negativo.
WTO >select months_between(date'2011-02-28', date'2011-05-07')
2 from dual;
MONTHS_BETWEEN(DATE'2011-02-28',DATE'2011-05-07')
-------------------------------------------------
-2,322580645
MONTHS_BETWEEN(DATE'2011-05-07',DATE'2011-02-28')
-------------------------------------------------
2,3225806452
MONTHS_BETWEEN(DATE'2011-02-28',DATE'2011-03-28')
-------------------------------------------------
224
-1
MONTHS_BETWEEN(DATE'2011-02-28',DATE'2011-03-30')
-------------------------------------------------
-1,064516129
MONTHS_BETWEEN(DATE'2011-02-28',DATE'2011-03-31')
-------------------------------------------------
-1
MONTHS_BETWEEN(DATE'2011-02-28',DATE'2011-04-01')
-------------------------------------------------
-1,129032258
LAST_DAY
La funzione LAST_DAY riceve in input una data e restituisce lultimo
giorno del mese in cui cade la data in input. La parte ore-minuti-secondi resta
inalterata.
WTO >select date'2011-03-05', last_day(date'2011-03-05')
2 from dual;
DATE'2011-03-05' LAST_DAY(DATE'2011-
------------------- -------------------
05-03-2011 00:00:00 31-03-2011 00:00:00
SYSDATE LAST_DAY(SYSDATE)
------------------- -------------------
13-02-2011 17:58:00 28-02-2011 17:58:00
NEXT_DAY
La funzione NEXT_DAY riceve in input una data ed il nome di un
giorno della settimana. Restituisce il primo giorno successivo al primo
parametro che cada nel giorno della settimana indicato come secondo
parametro. Oggi domenica, chiedendo
NEXT_DAY(SYSDATE, 'MARTEDI')
SYSDATE NEXT_DAY(SYSDATE,'M
------------------- -------------------
13-02-2011 18:00:38 15-02-2011 18:00:38
225
Se la data in input cade gi nel giorno indicato nel secondo parametro
la funzione NEXT_DAY equivale allaggiunta di una settimana.
WTO >select sysdate, next_day(sysdate, 'domenica')
2 from dual;
SYSDATE NEXT_DAY(SYSDATE,'D
------------------- -------------------
13-02-2011 18:09:36 20-02-2011 18:09:36
Session altered.
SYSDATE NEXT_DAY(SYSDATE,'T
------------------- -------------------
13-02-2011 18:12:21 15-02-2011 18:12:21
ROUND e TRUNC
La funzione ROUND arrotonda una data al giorno pi vicino.
WTO >select round(sysdate) from dual;
ROUND(SYSDATE)
-------------------
14-02-2011 00:00:00
SYSDATE ROUND(SYSDATE,'HH')
------------------- -------------------
13-02-2011 18:15:05 13-02-2011 18:00:00
226
La funzione TRUNC opera come la ROUND ma applica un
troncamento anzich un arrotondamento.
WTO >select trunc(sysdate) from dual;
TRUNC(SYSDATE)
-------------------
13-02-2011 00:00:00
SYSDATE TRUNC(SYSDATE,'HH')
------------------- -------------------
13-02-2011 18:19:02 13-02-2011 18:00:00
CURRENT_DATE e CURRENT_TIMESTAMP
La funzione CURRENT_DATE restituisce la data corrente applicando il
fuso orario della sessione (laddove invece la SYSDATE applica sempre il
fuso orario del database). SYSDATE diversa da CURRENT_DATE solo
quando il client che instanzia la sessione ed il server si trovano in due fusi
orari differenti. In una situazione standard (client e server nello stesso fuso
orario) si avr.
WTO >select sysdate, current_date
2 from dual;
SYSDATE CURRENT_DATE
------------------- -------------------
13-02-2011 18:21:04 13-02-2011 18:21:05
Session altered.
SYSDATE CURRENT_DATE
------------------- -------------------
13-02-2011 18:22:21 13-02-2011 09:22:22
Session altered.
SYSTIMESTAMP CURRENT_TIMESTAMP
--------------------------------- ---------------------------------
13-FEB-11 18:26:35,478507 +01:00 13-FEB-11 18:26:35,478528 +01:00
227
WTO >alter session set time_zone='-8:0';
Session altered.
SYSTIMESTAMP CURRENT_TIMESTAMP
--------------------------------- ---------------------------------
13-FEB-11 18:26:46,593435 +01:00 13-FEB-11 09:26:46,593459 -08:00
EXTRACT
La funzione EXTRACT consente di estrarre da un TIMESTAMP uno
degli elementi che lo compone, ad esempio il mese, il giorno oppure il
minuto. Gli elementi che possono essere estratti da un TIMESTAMP sono:
lanno (YEAR), il mese (MONTH), il giorno (DAY), lora (HOUR), il minuto
(MINUTE), il secondo (SECOND), lora del fuso orario (TIMEZONE_HOUR),
il minuto del fuso orario (TIMEZONE_MINUTE), la regione del fuso orario
(TIMEZONE_REGION), la stringa dabbreviazione del fuso orario
(TIMEZONE_ABBR).
Se si prova ad applicare la funzione ad una data anzich un timestamp
si ottiene un errore:
WTO >select extract(hour from data_fattura) from fatture;
select extract(hour from data_fattura) from fatture
*
ERRORE alla riga 1:
ORA-30076: invalid extract field for extract source
Per questo motivo creiamo una tabella T contenente una colonna COL
di tipo TIMESTAMP.
WTO >create table t (col timestamp);
Tabella creata.
Creata 1 riga.
EXTRACT(HOURFROMCOL)
--------------------
18
EXTRACT(SECONDFROMCOL) EXTRACT(SECONDFROMSYSTIMESTAMP)
228
---------------------- -------------------------------
54,280232 1,345504
EXTRACT(HOURFROMTO_TIMESTAMP(DATA_FATTURA))
-------------------------------------------
0
0
0
0
0
EXTRACT(DAYFROMTO_TIMESTAMP(DATA_FATTURA))
------------------------------------------
1
1
20
1
1
EXTRACT(MONTHFROMTO_TIMESTAMP(DATA_FATTURA))
--------------------------------------------
10
12
10
2
12
LAST_DAY(
229
---------
30-NOV-10
'12,3'+5
----------
17,3
TO_CHAR(S
---------
22-FEB-11
TO_CHAR(SY
----------
22/02/2011
230
TO_CHAR(5.3
-----------
5,30
TO_DATE
La funzione TO_DATE consente di convertire una stringa in data.
WTO >select to_date('12-nov-10') from dual;
TO_DATE('
---------
12-NOV-10
TO_DATE('
---------
12-NOV-10
TO_NUMBER
La funzione TO_NUMBER converte una stringa in numero. Anche in
questo caso opzionalmente possibile indicare il formato numerico in cui la
stringa espressa.
WTO >select to_number('123,4') from dual;
TO_NUMBER('123,4')
------------------
123,4
231
TO_NUMBER('123.123,4','999G999D99')
-----------------------------------
123123,4
TO_TIMESTAMP
La funzione TO_TIMESTAMP molto simile alla TO_DATE ma
trasforma una stringa in TIMESTAMP.
WTO >select to_timestamp('12-nov-10 22:10:33,123456')
2 from dual;
TO_TIMESTAMP('12-NOV-1022:10:33,123456')
-----------------------------------------------------------------
12-NOV-10 22:10:33,123456000
SYSDATE
---------
22-FEB-11
T
-
2
T
-
3
232
Il codice di formato dd stampa il giorno del mese a due cifre.
WTO >select to_char(sysdate,'dd') from dual;
TO
--
22
TO_
---
053
TO
--
02
Session altered.
TO_
---
may
Modificata sessione.
TO_
---
Mag
Session altered.
TO_CHAR(D
---------
May
233
Modificata sessione.
TO_CHAR(D
---------
maggio
T
-
1
TO
--
11
TO_
---
011
TO_C
----
2011
TO
--
10
TO
--
22
234
TO
--
42
TO
--
42
TO_CH
-----
81769
TO_CHAR(SYSDATE,'DD
-------------------
22-02-2011 22:43:24
TO_CHAR(SYSDATE,'"OGGIE''IL
---------------------------
oggi e' il 22 di febbraio .
235
TO_CHAR(123456
--------------
123.456,234
TO_CHAR(123456
--------------
123.456,200
TO_CHAR(123456
--------------
0.123.456,234
TO_CHAR(123456
--------------
0.123.456,200
TO_CHAR
-------
,30
TO_CHAR
-------
000,30
TO_CHAR
-------
0,30
236
NVL
La funzione NVL consente specificare due parametri. La funzione
restituisce il primo se questo NOT NULL, altrimenti il secondo.
WTO >select cod_fisc from clienti;
COD_FISC
----------------
RSSMRC70R20H501X
VRDMTT69S02H501X
NRILCU77A22F205X
SPSGNN71B10F839X
RSSPSQ70C14F839X
Selezionate 8 righe.
NVL(COD_FISC,'VALORENO
----------------------
RSSMRC70R20H501X
VALORE NON DISPONIBILE
VRDMTT69S02H501X
NRILCU77A22F205X
VALORE NON DISPONIBILE
SPSGNN71B10F839X
RSSPSQ70C14F839X
VALORE NON DISPONIBILE
Selezionate 8 righe.
A B C
---------- ---------- ---------
test1 1 22-FEB-11
test2 22-FEB-11
test3 3
test4
237
2 from test;
A NVL(B,9) NVL(C,SYS
---------- ---------- ---------
test1 1 22-FEB-11
test2 9 22-FEB-11
test3 3 25-FEB-11
test4 9 25-FEB-11
NVL2
La funzione NVL2 riceve in input tre parametri. Se il primo parametro
diverso da NULL ritorna il secondo parametro, altrimenti il terzo.
WTO >select nvl2(cod_fisc,'VALORIZZATO','NON VALORIZZATO')
2 from clienti;
NVL2(COD_FISC,'
---------------
VALORIZZATO
NON VALORIZZATO
VALORIZZATO
VALORIZZATO
NON VALORIZZATO
VALORIZZATO
VALORIZZATO
NON VALORIZZATO
Selezionate 8 righe.
NVL2(B,'VALORIZ
---------------
VALORIZZATO
NON VALORIZZATO
VALORIZZATO
NON VALORIZZATO
NVL2(C,'VALORIZ
---------------
VALORIZZATO
VALORIZZATO
NON VALORIZZATO
NON VALORIZZATO
COALESCE
La funzione COALESCE una generalizzazione della NVL. Riceve in
input un numero a piacere di espressioni e ritorna la prima che diversa da
NULL.
WTO >drop table test;
Tabella eliminata.
238
WTO >insert into test values ('A','B','C','D');
Creata 1 riga.
A B C D
---------- ---------- ---------- ----------
A B C D
@ B C D
@ @ C D
@ @ @ D
@ @ @ @
COALESCE(A
----------
A
B
C
D
@
COALESCE(COD_FIS
----------------
RSSMRC70R20H501X
NON VALORIZZATO
VRDMTT69S02H501X
NRILCU77A22F205X
NON VALORIZZATO
SPSGNN71B10F839X
RSSPSQ70C14F839X
NON VALORIZZATO
Selezionate 8 righe.
LNNVL
La funzione LNNVL riceve in input una condizione e ritorna TRUE
quando la condizione vera oppure quando la condizione a falsa a causa di
239
valori NULL. Se, ad esempio, cerchiamo tutti i codici fiscali che cominciano
per R otteniamo
WTO >select nome, cod_fisc from clienti;
NOME COD_FISC
-------- ----------------
MARCO RSSMRC70R20H501X
GIOVANNI @
MATTEO VRDMTT69S02H501X
LUCA NRILCU77A22F205X
AMBROGIO @
GENNARO SPSGNN71B10F839X
PASQUALE RSSPSQ70C14F839X
VINCENZO @
Selezionate 8 righe.
NOME
--------
MARCO
PASQUALE
Ci sono solo due codici che cominciano per R. Ce ne sono altri tre che
non cominciano per R e ce ne sono tre che sono UNKNOWN, non si sa se
cominciano per R oppure no perch il dato non presente nel sistema. Noi
potremmo voler vedere i nomi dei clienti cha hanno il codice fiscale che
comincia per R oppure non ha affatto il codice fiscale. Possiamo ottenere
questo risultato utilizzando nella WHERE la funzione LNNVL
WTO >select nome from clienti
2 where lnnvl(cod_fisc like 'R%');
NOME
--------
GIOVANNI
MATTEO
LUCA
AMBROGIO
GENNARO
VINCENZO
Selezionate 6 righe.
NOME NULLIF(NOME,'MARCO')
-------- ------------------------------
MARCO @
GIOVANNI GIOVANNI
240
MATTEO MATTEO
LUCA LUCA
AMBROGIO AMBROGIO
GENNARO GENNARO
PASQUALE PASQUALE
VINCENZO VINCENZO
Selezionate 8 righe.
COD_FISC NULLIF(COD_FISC,
---------------- ----------------
RSSMRC70R20H501X RSSMRC70R20H501X
@ @
VRDMTT69S02H501X VRDMTT69S02H501X
NRILCU77A22F205X NRILCU77A22F205X
@ @
SPSGNN71B10F839X SPSGNN71B10F839X
RSSPSQ70C14F839X RSSPSQ70C14F839X
@ @
Selezionate 8 righe.
Dove
241
source_string la stringa in cui cercare;
pattern l'espressione regolare;
position la posizione a partire dalla quale bisogna cercare;
occurrence l'occorrenza richiesta;
return_option pu valere 0 se si desidera la posizione del primo
carattere della sottostringa trovata, 1 se si desidera la posizione
del primo carattere successivo alla sottostringa trovata;
match_parameter un flag che pu valere:
i (ricerca case-insensitive),
c (ricerca case-sensitive),
n (il carattere jolly '.' trova anche il ritorno a capo),
m (interpreta la stringa in modalit multi-linea)
Solo i primi due parametri sono obbligatori.
Facciamo un esempio: cerchiamo nella stringa 'Questa una stringa di
prova che mi consente di illustrare le regex in Oracle' la seconda parola
composta di due lettere:
WTO >WITH T AS (
2 SELECT 'Questa una stringa di prova che mi consente
3 di illustrare le regex in Oracle' str from dual)
4 Select str, REGEXP_INSTR(str,'(^|\ )[[:alpha:]]{2}($|\ )',
5 1, 2)+1 pos
6 FROM t;
STR POS
-------------------------------------------------- ----------
Questa una stringa di prova che mi consente 35
di illustrare le regex in Oracle
REGEXP_REPLACE
La funzione REGEXP_REPLACE consente di sostituire una stringa
trovata mediante espressione regolare con un'altra stringa data:
REGEXP_REPLACE(source_string, pattern, replace_string, position,
occurrence, match_parameter)
Dove
source_string la stringa in cui effettuare la ricerca e la
sostituzione;
pattern l'espressione regolare;
replace_string la stringa da sostituire a quanto trovato mediante
il pattern;
position la posizione a partire dalla quale bisogna cercare;
occurrence l'occorrenza richiesta;
match_parameter come nella REGEXP_INSTR.
242
Se quindi vogliamo sostituire, nella stringa dell'esempio precedente, la
seconda parola di due caratteri con una X, dobbiamo fare:
WTO >WITH T AS (
2 SELECT 'Questa una stringa di prova che mi consente
3 di illustrare le regex in Oracle' str from dual)
4 Select REGEXP_REPLACE(str,'(^|\ )[[:alpha:]]{2}($|\ )',
5 ' X ',1, 2) newstr
6 FROM t;
NEWSTR
--------------------------------------------------------------
Questa una stringa di prova che X consente
di illustrare le regex in Oracle
REGEXP_SUBSTR
La funzione REGEXP_SUBSTR consente di estrarre una sottostringa:
REGEXP_SUBSTR (source_string , pattern, position, occurrence,
match_parameter)
Dove
source_string la stringa in cui effettuare la ricerca e da cui
estrarre la sottostringa;
pattern l'espressione regolare;
position la posizione a partire dalla quale bisogna cercare;
occurrence l'occorrenza richiesta;
match_parameter come nella REGEXP_INSTR.
Quindi per estrarre la seconda parola da due caratteri:
WTO >WITH T AS (
2 SELECT 'Questa una stringa di prova che mi
3 consente di illustrare le regex in Oracle' str from dual)
4 Select str,
5 trim(REGEXP_SUBSTR(str,'(^|\ )[[:alpha:]]{2}($|\ )'
6 ,1, 2)) substr
7* FROM t
STR SUBSTR
-------------------------------------------------- ------
Questa una stringa di prova che mi di
consente di illustrare le regex in Oracle
REGEXP_COUNT
La funzione REGEXP_COUNT ci consente di contare le occorrenze
nella source string che verificano il pattern:
REGEXP_COUNT (source_char , pattern, position, match_param)
Dove
source_char la stringa in cui effettuare la ricerca;
pattern l'espressione regolare;
position la posizione a partire dalla quale bisogna cercare;
243
return_option come nella REGEXP_INSTR.
Quindi per ottenere il numero di parole di due caratteri:
WTO> WITH T AS (
2 SELECT 'Questa una stringa di prova che mi consente
3 di illustrare le regex in Oracle' str from dual)
4 Select str,
5 REGEXP_COUNT(str,'(^|\ )[[:alpha:]]{2}($|\ )',1) count
6 FROM t;
STR COUNT
-------------------------------------------------- ----------
Questa una stringa di prova che mi consente 4
di illustrare le regex in Oracle
STR SUBSTR
-------------------------------------------------- ------
Questa una stringa di prova che mi consente di
di illustrare le regex in Oracle
REGEXP_LIKE
La condizione REGEXP_LIKE torna boolean e pu essere utilizzata
nella WHERE o nella HAVING di una query:
REGEXP_LIKE (source_string, pattern, match_parameter)
Dove
source_string la stringa in cui effettuare la ricerca;
pattern l'espressione regolare;
match_parameter come nella REGEXP_INSTR.
REGEXP_LIKE(str,ptrn,mp) logicamente equivalente a
REGEXP_INSTR(str,ptrn,1,1,mp)>0
244
Tiriamo per esempio fuori tutte le stringhe che hanno almeno una
parola da due caratteri:
WTO> WITH T AS (
2 SELECT 'Stringa senza parole di2' str from dual union
3 SELECT 'prima Stringa con parole di 2 caratteri' from dual
4 union
5 SELECT 'seconda Stringa con parole di 2 caratteri' from dual
6 union
7 SELECT 'Altra Stringa senza parole di2' from dual
8 )
9 Select str
10 from t
11 where REGEXP_LIKE(str,'(^|\ )[[:alpha:]]{2}($|\ )');
STR
--------------------------------------------------
prima Stringa con parole di 2 caratteri
seconda Stringa con parole di 2 caratteri
STR
--------------------------------------------------
prima Stringa con parole di 2 caratteri
seconda Stringa con parole di 2 caratteri
245
4 3 01-FEB-11 1000 N
5 5 01-DIC-10 500 S
NOME CF?
-------- ------
MARCO CON CF
GIOVANNI NO CF
MATTEO CON CF
LUCA CON CF
AMBROGIO NO CF
GENNARO CON CF
PASQUALE CON CF
VINCENZO NO CF
Selezionate 8 righe.
246
Sebbene la funzione DECODE consenta solo confronti con insiemi
discreti di valori, con un po di fantasia essa pu essere utilizzata anche per
gestire insiemi continui. Ipotizziamo ad esempio di voler, per ogni fattura,
indicare se essa ha un importo minore, maggiore o uguale a 500 euro.
WTO >select num_fattura, importo,
2 decode(sign(importo-500),-1,'<500',0,'=500',1,'>500') fascia
3 from fatture;
247
WTO >select num_fattura, data_fattura,
2 CASE pagata when 'S' then 'PAGATA'
3 when 'N' then 'NON PAGATA' END "pagata?"
4 from fatture;
NUM_FATTURA DATA_FATT pagata?
----------- --------- ----------
1 01-OTT-10 PAGATA
2 01-DIC-10 NON PAGATA
3 20-OTT-10 PAGATA
4 01-FEB-11 NON PAGATA
5 01-DIC-10 PAGATA
WTO >select num_fattura, data_fattura,
2 CASE num_fattura when 1 then 'PRIMA'
3 when 2 then 'SECONDA'
4 else 'SUCCESSIVE' end posiz
5 from fatture;
NUM_FATTURA DATA_FATT POSIZ
----------- --------- ----------
1 01-OTT-10 PRIMA
2 01-DIC-10 SECONDA
3 20-OTT-10 SUCCESSIVE
4 01-FEB-11 SUCCESSIVE
5 01-DIC-10 SUCCESSIVE
WTO >select nome,
2 case cod_fisc when null then 'NO CF'
3 else 'CON CF' end "CF?"
4 from clienti;
NOME CF?
-------- ------
MARCO CON CF
GIOVANNI CON CF
MATTEO CON CF
LUCA CON CF
AMBROGIO CON CF
GENNARO CON CF
PASQUALE CON CF
VINCENZO CON CF
Selezionate 8 righe.
Come si vede, tre query su quattro hanno dato lo stesso risultato una,
invece, errata. La struttura CASE utilizzata nella modalit appena mostrata,
248
non in grado di gestire i valori nulli. O meglio li gestisce come UNKNOWN.
Di conseguenza nella terza query la condizione WHEN NULL sempre falsa.
Per ovviare a questo problema la query pu essere riscritta utilizzando
la seconda sintassi ammessa dalla struttura CASE.
WTO >select nome,
2 case when (cod_fisc is null) then 'NO CF'
3 else 'CON CF' end "CF?"
4 from clienti;
NOME CF?
-------- ------
MARCO CON CF
GIOVANNI NO CF
MATTEO CON CF
LUCA CON CF
AMBROGIO NO CF
GENNARO CON CF
PASQUALE CON CF
VINCENZO NO CF
Selezionate 8 righe.
GREATEST(-3,5,1,7,2,-4)
-----------------------
7
249
GREATEST(
---------
27-FEB-11
GREATE
------
SANDRO
LEAST
La funzione LEAST identica alla GREATEST con la differenza che
ritorna il pi piccolo dei parametri ricevuti.
WTO >select least(-3,5,1,7,2,-4)
2 from dual;
LEAST(-3,5,1,7,2,-4)
--------------------
-4
LEAST(SYS
---------
22-FEB-11
LEAST('
-------
ALBERTO
250
La seconda sintassi, utilizzata da sempre in Oracle, prevede di
indicare nella clausola FROM solo le tabelle da cui estrarre i dati, spostando
nella clausola WHERE le condizioni da utilizzare per abbinare correttamente
i record.
In questo manuale sar solo fatto un accenno alla prima sintassi e
sar invece utilizzata sempre la seconda. Questa scelta deriva da tre
considerazioni. La prima che, per coerenza con il resto del manuale, si
preferisce il dialetto SQL Oracle allo standard ANSI. La seconda ragione
che la sintassi ANSI risulta, quanto meno nella modesta esperienza
dellautore, pi complessa da apprendere per i principianti. Lultima ragione
che la tardiva introduzione della sintassi standard in Oracle ha fatto in modo
che la maggior parte del codice SQL e PL/SQL oggi esistente su DB Oracle
sia scritto con la sintassi non standard.
251
MATTEO VERDI VIA DEL MARE, 8 G811 M297 FIUMICINO RM
MATTEO VERDI VIA DEL MARE, 8 G811 F205 MILANO MI
MATTEO VERDI VIA DEL MARE, 8 G811 G686 PIOLTELLO MI
MATTEO VERDI VIA DEL MARE, 8 G811 E415 LAINATE MI
MATTEO VERDI VIA DEL MARE, 8 G811 F839 NAPOLI NA
MATTEO VERDI VIA DEL MARE, 8 G811 G964 POZZUOLI NA
MATTEO VERDI VIA DEL MARE, 8 G811 G902 PORTICI NA
LUCA NERI VIA TORINO, 30 F205 H501 ROMA RM
LUCA NERI VIA TORINO, 30 F205 G811 POMEZIA RM
LUCA NERI VIA TORINO, 30 F205 M297 FIUMICINO RM
LUCA NERI VIA TORINO, 30 F205 F205 MILANO MI
LUCA NERI VIA TORINO, 30 F205 G686 PIOLTELLO MI
LUCA NERI VIA TORINO, 30 F205 E415 LAINATE MI
LUCA NERI VIA TORINO, 30 F205 F839 NAPOLI NA
LUCA NERI VIA TORINO, 30 F205 G964 POZZUOLI NA
LUCA NERI VIA TORINO, 30 F205 G902 PORTICI NA
AMBROGIO COLOMBO PIAZZA DUOMO, 1 F205 H501 ROMA RM
AMBROGIO COLOMBO PIAZZA DUOMO, 1 F205 G811 POMEZIA RM
AMBROGIO COLOMBO PIAZZA DUOMO, 1 F205 M297 FIUMICINO RM
AMBROGIO COLOMBO PIAZZA DUOMO, 1 F205 F205 MILANO MI
AMBROGIO COLOMBO PIAZZA DUOMO, 1 F205 G686 PIOLTELLO MI
AMBROGIO COLOMBO PIAZZA DUOMO, 1 F205 E415 LAINATE MI
AMBROGIO COLOMBO PIAZZA DUOMO, 1 F205 F839 NAPOLI NA
AMBROGIO COLOMBO PIAZZA DUOMO, 1 F205 G964 POZZUOLI NA
AMBROGIO COLOMBO PIAZZA DUOMO, 1 F205 G902 PORTICI NA
GENNARO ESPOSITO VIA CARACCIOLO, 100 F839 H501 ROMA RM
GENNARO ESPOSITO VIA CARACCIOLO, 100 F839 G811 POMEZIA RM
GENNARO ESPOSITO VIA CARACCIOLO, 100 F839 M297 FIUMICINO RM
GENNARO ESPOSITO VIA CARACCIOLO, 100 F839 F205 MILANO MI
GENNARO ESPOSITO VIA CARACCIOLO, 100 F839 G686 PIOLTELLO MI
GENNARO ESPOSITO VIA CARACCIOLO, 100 F839 E415 LAINATE MI
GENNARO ESPOSITO VIA CARACCIOLO, 100 F839 F839 NAPOLI NA
GENNARO ESPOSITO VIA CARACCIOLO, 100 F839 G964 POZZUOLI NA
GENNARO ESPOSITO VIA CARACCIOLO, 100 F839 G902 PORTICI NA
PASQUALE RUSSO VIA GIULIO CESARE, 119 F839 H501 ROMA RM
PASQUALE RUSSO VIA GIULIO CESARE, 119 F839 G811 POMEZIA RM
PASQUALE RUSSO VIA GIULIO CESARE, 119 F839 M297 FIUMICINO RM
PASQUALE RUSSO VIA GIULIO CESARE, 119 F839 F205 MILANO MI
PASQUALE RUSSO VIA GIULIO CESARE, 119 F839 G686 PIOLTELLO MI
PASQUALE RUSSO VIA GIULIO CESARE, 119 F839 E415 LAINATE MI
PASQUALE RUSSO VIA GIULIO CESARE, 119 F839 F839 NAPOLI NA
PASQUALE RUSSO VIA GIULIO CESARE, 119 F839 G964 POZZUOLI NA
PASQUALE RUSSO VIA GIULIO CESARE, 119 F839 G902 PORTICI NA
VINCENZO AMATO VIA NAPOLI, 234 G964 H501 ROMA RM
VINCENZO AMATO VIA NAPOLI, 234 G964 G811 POMEZIA RM
VINCENZO AMATO VIA NAPOLI, 234 G964 M297 FIUMICINO RM
VINCENZO AMATO VIA NAPOLI, 234 G964 F205 MILANO MI
VINCENZO AMATO VIA NAPOLI, 234 G964 G686 PIOLTELLO MI
VINCENZO AMATO VIA NAPOLI, 234 G964 E415 LAINATE MI
VINCENZO AMATO VIA NAPOLI, 234 G964 F839 NAPOLI NA
VINCENZO AMATO VIA NAPOLI, 234 G964 G964 POZZUOLI NA
VINCENZO AMATO VIA NAPOLI, 234 G964 G902 PORTICI NA
Selezionate 72 righe.
Come si vede ognuno degli otto clienti stato associato ad ognuno dei
9 comuni, generando dunque un insieme di 72 record.
252
7.6.3 Inner join
Raramente lobiettivo del programmatore realizzare un prodotto
cartesiano. Normalmente lesigenza abbinare tra loro i dati estratti dalle
due tabelle secondo un criterio preciso.
Nellesempio precedente evidente che, per ogni cliente, non
interessano i dati relativi a tutti i comuni, ma solo i dati del comune in cui quel
cliente risiede. Alla query appena presentata, dunque, necessario
aggiungere una condizione di abbinamento, detta anche condizione di JOIN.
In questo caso la condizione di JOIN che il codice del comune presente in
COMUNI (COD_COMUNE) sia lo stesso presente nella tabella CLIENTI
(COMUNE). Si scriver dunque:
WTO >select nome, cognome, indirizzo, comune, cod_comune,
2 des_comune, provincia
3 from clienti, comuni
4 where comune=cod_comune;
Selezionate 8 righe.
Selezionate 8 righe.
254
Ovviamente se un cliente ha pi di un ordine oppure se un ordine ha
pi fatture I record di clienti o ordini sono moltiplicati. Viceversa, come gi
osservato, i clienti senza ordini o con ordini ma senza fatture non compaiono
affatto nella lista.
NUM_ORDINE NUM_FATTURA
---------- -----------
1 1
1 2
2 3
3 4
5 5
255
Nel nostro esempio le colonne coinvolte nella condizione di JOIN sono
il numero ordine di ORDINI (O.NUM_ORDINE) ed il numero ordine di fatture
(F.NUM_ORDINE). Abbiamo detto che vogliamo tutti gli ordini anche quelli
che non hanno fatture corrispondenti. Quindi la colonna in cui vogliamo
ignorare le mancanze di corrispondenze F.NUM_ORDINE. La condizione
di JOIN diventa dunque
O.NUM_ORDINE=F.NUM_ORDINE(+)
NUM_ORDINE NUM_FATTURA
---------- -----------
1 1
1 2
2 3
3 4
5 5
4
Selezionate 6 righe.
NUM_ORDINE NUM_FATTURA
---------- -----------
1 1
1 2
2 3
3 4
5 5
256
WTO> desc emp
Name Null? Type
----------------- -------- ------------
EMPNO NOT NULL NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NUMBER(2)
ENAME DEPTNO
---------- ----------
SMITH 20
ALLEN 30
WARD 30
JONES 20
MARTIN 30
BLAKE 30
CLARK 10
SCOTT 20
KING 10
TURNER 30
ADAMS 20
JAMES 30
FORD 20
MILLER 10
14 rows selected.
DEPTNO DNAME
---------- --------------
10 ACCOUNTING
20 RESEARCH
30 SALES
40 OPERATIONS
257
FORD 20 20 RESEARCH
ADAMS 20 20 RESEARCH
SMITH 20 20 RESEARCH
SCOTT 20 20 RESEARCH
WARD 30 30 SALES
TURNER 30 30 SALES
ALLEN 30 30 SALES
JAMES 30 30 SALES
BLAKE 30 30 SALES
MARTIN 30 30 SALES
14 rows selected.
1 row updated.
13 rows selected.
258
TURNER 30 30 SALES
BLAKE 30 30 SALES
MARTIN 30 30 SALES
WARD 30 30 SALES
ALLEN 30 30 SALES
FORD
14 rows selected.
14 rows selected.
259
---------- ---------- ---------- --------------
MILLER 10 10 ACCOUNTING
KING 10 10 ACCOUNTING
CLARK 10 10 ACCOUNTING
ADAMS 20 20 RESEARCH
SCOTT 20 20 RESEARCH
JONES 20 20 RESEARCH
SMITH 20 20 RESEARCH
JAMES 30 30 SALES
TURNER 30 30 SALES
BLAKE 30 30 SALES
MARTIN 30 30 SALES
WARD 30 30 SALES
ALLEN 30 30 SALES
FORD
40 OPERATIONS
15 rows selected.
Ovviamente, visto che ci sono sempre molte strade per giungere alla
medesima destinazione, c modo per ottenere lo stesso risultato in Oracle
senza utilizzare la FULL OUTER JOIN. Ce ne occuperemo nel paragrafo
successivo.
Nelle precedenti versioni di Oracle non era possibile mettere in outer
join pi tabelle con la stessa utilizzando la sintassi nativa. Era necessario
utilizzare la sintassi standard ANSI.
Questo limite stato superato in Oracle 12c. Per comprendere bene la
questione dobbiamo fare un esempio. Ipotizziamo di avere tre tabelle:
CLIENTI, PIANI e COMUNI create e popolate come segue:
260
insert into clienti values (5, 'Marco Gialli', 'P2G', 'F839');
insert into clienti values (6, 'Vittorio Grigi', 'P1G', 'H501');
6 rows selected.
COD DESCR
--- --------------------
P1G 1Gb mese flat
P2G 2Gb mese flat
P4G 4Gb mese flat
P8G 8Gb mese flat
CODI NOME
---- --------------------
H501 ROMA
F839 NAPOLI
F205 MILANO
L219 TORINO
6 rows selected.
PIANO CLIENTI
261
-------------------- ----------
1Gb mese flat 1
2Gb mese flat 3
4Gb mese flat 0
8Gb mese flat 2
COMUNE CLIENTI
-------------------- ----------
MILANO 0
NAPOLI 1
ROMA 2
TORINO 3
262
4Gb mese flat ROMA 0
4Gb mese flat TORINO 0
8Gb mese flat MILANO 0
8Gb mese flat NAPOLI 0
8Gb mese flat ROMA 0
8Gb mese flat TORINO 2
16 rows selected.
16 rows selected.
263
2Gb mese flat TORINO 1
4Gb mese flat MILANO 0
4Gb mese flat NAPOLI 0
4Gb mese flat ROMA 0
4Gb mese flat TORINO 0
8Gb mese flat MILANO 0
8Gb mese flat NAPOLI 0
8Gb mese flat ROMA 0
8Gb mese flat TORINO 2
16 righe selezionate.
264
DESCR NOME
-------------------- --------------------
2Gb mese flat Gianni Bianchi
8Gb mese flat Stefano Neri
2Gb mese flat Luca Rossi
8Gb mese flat Davide Verdi
2Gb mese flat Marco Gialli
1Gb mese flat Vittorio Grigi
6 righe selezionate.
DESCR NOME
-------------------- --------------------
2Gb mese flat Gianni Bianchi
8Gb mese flat Stefano Neri
2Gb mese flat Luca Rossi
8Gb mese flat Davide Verdi
2Gb mese flat Marco Gialli
1Gb mese flat Vittorio Grigi
4Gb mese flat
7 righe selezionate.
DESCR NOME
-------------------- --------------------
2Gb mese flat Gianni Bianchi
8Gb mese flat Stefano Neri
2Gb mese flat Luca Rossi
8Gb mese flat Davide Verdi
2Gb mese flat Marco Gialli
1Gb mese flat Vittorio Grigi
6 righe selezionate.
265
5 comune varchar2(4));
6 /
Tipo creato.
Funzione creata.
DESCR NOME
-------------------- ------------------------------
1Gb mese flat Vittorio Grigi
2Gb mese flat Gianni Bianchi
2Gb mese flat Luca Rossi
2Gb mese flat Marco Gialli
8Gb mese flat Stefano Neri
8Gb mese flat Davide Verdi
6 righe selezionate.
266
*
ERRORE alla riga 2:
ORA-00928: parola chiave SELECT mancante
7.7.1 UNION
Loperatore UNION consente di specificare due query distinte ed
ottenere come risultato lunione insiemistica dei risultati. Le due query
devono ovviamente estrarre lo stesso numero di colonne e le colonne che si
trovano nella stessa posizione nelle diverse query devono essere dello
stesso tipo di dato.
WTO >select nome, cognome from clienti
2 where cod_fisc is null
3 union
4 select nome, cognome from clienti
5 where comune='H501';
NOME COGNOME
------------------------------ ------------------------------
AMBROGIO COLOMBO
GIOVANNI BIANCHI
MARCO ROSSI
VINCENZO AMATO
NOME COGNOME
------------------------------ --------------------
MARCO ROSSI
GIOVANNI BIANCHI
AMBROGIO COLOMBO
VINCENZO AMATO
267
WTO >select nome, cognome from clienti
2 where cod_fisc is null
3 union
4 select nome, cod_cliente from clienti
5 where comune='H501';
select nome, cognome from clienti
*
ERRORE alla riga 1:
ORA-01790: expression must have same datatype as corresponding
expression
NOME COGNOME
------------------------------ ------------------------------
AMBROGIO COLOMBO
GIOVANNI BIANCHI
VIA LAURENTINA, 700 H501
VIA OSTIENSE, 850 H501
VINCENZO AMATO
NOME COGNOME
------------------------------ ---------------------
AMBROGIO COLOMBO
GIOVANNI BIANCHI
VIA LAURENTINA, 700 H501
VIA OSTIENSE, 850 H501
VINCENZO AMATO
NOME COGNOME
268
------------------------------ ---------------------
AMBROGIO COLOMBO
GIOVANNI BIANCHI
VIA LAURENTINA, 700 H501
VIA OSTIENSE, 850 H501
VINCENZO AMATO
NOME
------------------------------
AMBROGIO
GENNARO
GIOVANNI
LUCA
MARCO
MATTEO
PASQUALE
VINCENZO
15 rows selected.
269
7.7.2 UNION ALL
Loperatore UNION ALL si comporta come la UNION ma non scarta i
record duplicati.
WTO >select nome from clienti
2 union all
3 select nome from clienti;
NOME
------------------------------
MARCO
GIOVANNI
MATTEO
LUCA
AMBROGIO
GENNARO
PASQUALE
VINCENZO
MARCO
GIOVANNI
MATTEO
LUCA
AMBROGIO
GENNARO
PASQUALE
VINCENZO
Selezionate 16 righe.
270
La UNION ALL in generale pi performante della UNION perch,
non dovendo scartare i duplicati, Oracle non costretto ad ordinare i record
delle due query per trovare i record uguali.
7.7.3 INTERSECT
Loperatore INTERSECT restituisce lintersezione insiemistica dei due
insiemi di record estratti dalla due singole query.
WTO >select nome, cognome from clienti
2 where cod_fisc is not null;
NOME COGNOME
------------------------------ --------------------
LUCA NERI
MARCO ROSSI
PASQUALE RUSSO
GENNARO ESPOSITO
MATTEO VERDI
NOME COGNOME
------------------------------ --------------------
MARCO ROSSI
GIOVANNI BIANCHI
NOME COGNOME
------------------------------ --------------------
MARCO ROSSI
7.7.4 MINUS
Loperatore MINUS implementa il complemento insiemistico. Quando
due query vengono messe in relazione con questo operatore Oracle estrae i
record presenti nel risultato della prima query e non presenti nel risultato
della seconda.
WTO >select nome, cognome from clienti
2 where cod_fisc is not null;
NOME COGNOME
------------------------------ ------------------
LUCA NERI
MARCO ROSSI
PASQUALE RUSSO
GENNARO ESPOSITO
MATTEO VERDI
NOME COGNOME
271
------------------------------ ------------------
MARCO ROSSI
GIOVANNI BIANCHI
WTO >select nome, cognome from clienti where cod_fisc is not null
2 minus
3 select nome, cognome from clienti where comune='H501';
NOME COGNOME
------------------------------ ------------------
GENNARO ESPOSITO
LUCA NERI
MATTEO VERDI
PASQUALE RUSSO
NOME COGNOME
------------------------------ ------------------
GIOVANNI BIANCHI
AVG(IMPORTO)
------------
600
272
Un altro modo per ottenere lo stesso risultato mettere in JOIN la
tabella fatture con una subquery che ritorna solo limporto medio delle fatture.
Senza condizione di JOIN visto che la subquery restituisce una sola riga.
WTO >select num_fattura, importo, IMPORTO_MEDIO
2 from fatture, (select avg(importo) IMPORTO_MEDIO
3 from fatture);
NUM_FATTURA IMPORTO
----------- ----------
3 700
4 1000
NUM_FATTURA IMPORTO
----------- ----------
1 300
2 500
5 500
4 1000
3 700
273
loperatore >= in grado di gestire il confronto di un valore (IMPORTO in
quel caso) con un solo valore (il risultato della subquery).
WTO >select num_fattura, importo
2 from fatture
3 where importo>=(select importo from fatture);
where importo>=(select importo from fatture)
*
ERRORE alla riga 3:
ORA-01427: single-row subquery returns more than one row
NUM_ORDINE IMPORTO
---------- ----------
1 800
2 700
3 1000
4 1200
5 1700
NUM_FATTURA IMPORTO
----------- ----------
1 300
2 500
3 700
4 1000
5 500
NUM_FATTURA IMPORTO
----------- ----------
4 1000
NUM_FATTURA IMPORTO
----------- ----------
4 1000
274
3 700
ALL
Loperatore ALL ritorna VERO se la condizione a cui applicato vera
per tutti i record estratti dalla subquery.
Ipotizziamo ad esempio di volere estrarre gli ordini il cui importo
maggiore dellimporto di tutte le fatture esistenti.
WTO >select num_ordine, importo from ordini
2 where importo > ALL (select importo
3 from fatture);
NUM_ORDINE IMPORTO
---------- ----------
4 1200
5 1700
IN (subquery)
Loperatore IN del tutto analogo a quello gi incontrato in
precedenza. La differenza consiste nel fatto che la lista dei valori ottenuta
mediante una subquery.
Elenco di tutti i clienti residenti in provincia di Roma.
WTO >select nome, cognome, indirizzo
2 from clienti
3 where comune in (select cod_comune
4 from comuni
5 where provincia='RM');
EXISTS
Loperatore EXISTS ritorna VERO se la subquery estrae almeno un
record.
Si ipotizzi ad esempio di volere visualizzare nome e cognome dei
clienti che hanno fatto almeno un ordine.
275
WTO >select nome, cognome
2 from clienti c
3 where exists (select * from ordini o
4 where o.cod_cliente = c.cod_cliente);
NOME COGNOME
-------- --------
MARCO ROSSI
GIOVANNI BIANCHI
LUCA NERI
AMBROGIO COLOMBO
PASQUALE RUSSO
NOME COGNOME
-------- --------
MARCO ROSSI
GIOVANNI BIANCHI
LUCA NERI
AMBROGIO COLOMBO
PASQUALE RUSSO
Creata 1 riga.
NOME COGNOME
-------- --------
MARCO ROSSI
MARCO ROSSI
GIOVANNI BIANCHI
LUCA NERI
AMBROGIO COLOMBO
PASQUALE RUSSO
Selezionate 6 righe.
276
3 where exists (select * from ordini o
4 where o.cod_cliente = c.cod_cliente);
NOME COGNOME
-------- --------
MARCO ROSSI
GIOVANNI BIANCHI
LUCA NERI
AMBROGIO COLOMBO
PASQUALE RUSSO
NOME COGNOME
-------- --------
GIOVANNI BIANCHI
LUCA NERI
MARCO ROSSI
AMBROGIO COLOMBO
PASQUALE RUSSO
AVG(IMPORTO)
------------
600
277
WTO >select num_fattura, importo,
2 600 IMPORTO_MEDIO
3 from fatture;
NOME MAX(NUM_ORDINE)
-------- ---------------
AMBROGIO 4
PASQUALE 5
LUCA 3
MARCO 1
GIOVANNI 2
NOME MAX_NUM_ORD
-------- -----------
MARCO 1
GIOVANNI 2
MATTEO
LUCA 3
AMBROGIO 4
GENNARO
PASQUALE 5
VINCENZO
Selezionate 8 righe.
278
5 ;
NOME MAX(NUM_ORDINE)
-------- ---------------
MATTEO
AMBROGIO 4
PASQUALE 5
LUCA 3
VINCENZO
MARCO 1
GIOVANNI 2
GENNARO
Selezionate 8 righe.
279
4 from fatture, t;
7.9.2 COMMIT
Per default ogni transazione legge solo i dati esplicitamente
confermati da altre transazioni ed i dati modificati, anche se ancora non
confermati, nella propria transazione.
Facciamo un esempio. Apriamo due sessioni di SQL*plus utilizzando
lo stesso utente. Negli esempi seguenti ho utilizzato il prompt WT1 per
indicare la prima sessione ed il prompt WT2 per indicare la seconda
sessione.
280
La sessione 1 crea una tabella.
WT1 >create table test_tr (a number, b varchar2(10));
Tabella creata.
Creata 1 riga.
A B
---------- ----------
1 ins wt1
Commit completato.
A B
---------- ----------
1 ins wt1
Creata 1 riga.
Tabella creata.
281
Lutente non ha esplicitamente confermato linsert ma Oracle ha
implicitamente confermato e chiuso lintera transazione al comando DDL.
Laltra sessione, infatti, vede entrambe le modifiche.
WT2 >select * from test_tr;
A B
---------- ----------
1 ins wt1
2 ins wt1
7.9.3 ROLLBACK
Il comando ROLLBACK consente di annullare tutte le modifiche
apportate durante la transazione.
WT1 >insert into test_tr values (3,'ins wt1');
Creata 1 riga.
Creata 1 riga.
Creata 1 riga.
A B
---------- ----------
1 ins wt1
2 ins wt1
3 ins wt1
4 ins wt1
X
----------
100
WT1 >rollback;
Rollback completato.
A B
---------- ----------
1 ins wt1
2 ins wt1
282
Nessuna riga selezionata
7.9.4 SAVEPOINT
Il comando SAVEPOINT consente di inserire dei segnaposto
allinterno della transazione in modo che sia possibile, mediante una opzione
del comando ROLLBACK, annullare parzialmente le modifiche fatte durante
la transazione.
Nellesempio seguente vengono definiti alcuni savepoint allinterno
della transazione e poi si annullano alcuni comandi eseguiti.
Innanzitutto si inserisce una riga in TEST_TR e si crea un savepoint.
WT1 >insert into test_tr values (3,'ins wt1');
Creata 1 riga.
Creato savepoint.
Creata 1 riga.
Creato savepoint.
Creata 1 riga.
A B
---------- ----------
1 ins wt1
2 ins wt1
3 ins wt1
4 ins wt1
X
----------
200
283
WT1 >rollback to rec_200;
Rollback completato.
A B
---------- ----------
1 ins wt1
2 ins wt1
3 ins wt1
X
----------
200
Rollback completato.
A B
---------- ----------
1 ins wt1
2 ins wt1
3 ins wt1
Commit completato.
A B
---------- ----------
1 ins wt1
2 ins wt1
3 ins wt1
284
Rollback completato.
A B
---------- ----------
1 ins wt1
2 ins wt1
3 ins wt1
Impostata transazione.
A B
---------- ----------
1 ins wt1
2 ins wt1
3 ins wt1
Creata 1 riga.
WT2 >commit;
Commit completato.
A B
---------- ----------
1 ins wt1
285
2 ins wt1
3 ins wt1
Rollback completato.
A B
---------- ----------
1 ins wt1
2 ins wt1
3 ins wt1
4 ins wt2
Impostata transazione.
A B
---------- ----------
1 ins wt1
2 ins wt1
3 ins wt1
4 ins wt2
286
Aggiornata 1 riga.
A B
---------- ----------
1 agg
2 ins wt1
3 ins wt1
4 ins wt2
Commit completato.
Aggiornata 1 riga.
A B
---------- ----------
10 agg
2 ins wt1
3 ins wt1
4 ins wt2
WT2 >commit;
Commit completato.
A B
---------- ----------
10 agg
2 ins wt1
3 ins wt1
287
4 ins wt2
Aggiornata 1 riga.
A B
---------- ----------
10 agg
2 agg2
3 ins wt1
4 ins wt2
Impostata transazione.
A B
---------- ----------
10 agg
2 ins wt1
3 ins wt1
4 ins wt2
Commit completato.
A B
---------- ----------
10 agg
2 ins wt1
3 ins wt1
4 ins wt2
288
La transazione serializzabile partita quando la modifica della
sessione 2 non era stata ancora committata e dunque questa transazione
non pu utilizzare quei dati anche se essi sono stati successivamente
confermati.
Tabella/e bloccata/e.
La sessione 2 va avanti.
WT2 >update test_tr
2 set b='agg3'
3 where a=3;
Aggiornata 1 riga.
A B
---------- ----------
10 agg
2 agg2
3 agg3
4 ins wt2
WT2 >commit;
Commit completato.
289
Ipotizziamo che la sessione 2 esegua un comando di update.
WT2 >update test_tr
2 set b='agg4'
3 where a=4;
Aggiornata 1 riga.
Aggiornata 1 riga.
Aggiornata 1 riga.
290
ORA-00060: deadlock detected while waiting for resource
Rollback completato.
Aggiornata 1 riga.
WT2 >commit;
Commit completato.
7.10.1 GRANT
Il comando GRANT consente di concedere ad un utente il privilegio di
eseguire una determinata azione su un oggetto.
La sintassi del comando
GRANT <privilegio> ON <oggetto> TO <utente>
Concessione riuscita.
ENAME JOB
291
---------- ---------
SMITH CLERK
ALLEN SALESMAN
WARD SALESMAN
JONES MANAGER
MARTIN SALESMAN
BLAKE MANAGER
CLARK MANAGER
SCOTT ANALYST
KING PRESIDENT
TURNER SALESMAN
ADAMS CLERK
JAMES CLERK
FORD ANALYST
MILLER CLERK
Selezionate 14 righe.
Concessione riuscita.
7.10.2 REVOKE
La revoca di uno o pi privilegi precedentemente concessi ad un
utente si realizza con il comando REVOKE. La sintassi
REVOKE <privilegio> ON <oggetto> FROM <utente>
292
SCO >revoke update on emp from wto_esempio;
Revoca riuscita.
7.10.3 RUOLI
Pu essere utile accorpare in un unico contenitore un insieme di
privilegi in modo da poterli concedere o revocare tutti insieme. Un contenitore
di privilegi si chiama RUOLO.
La creazione del ruolo si realizza col comando CREATE ROLE.
Lassociazione al ruolo dei privilegi si esegue mediante il comando GRANT.
Ad esempio ipotizziamo che lutente SCOTT voglia creare un ruolo
RUOLO_TEST che includa i privilegi di SELECT ed UPDATE su EMP ed il
privilegio di SELECT su DEPT.
SCO >create role ruolo_test;
Ruolo creato.
Concessione riuscita.
Concessione riuscita.
Concessione riuscita.
Revoca riuscita.
293
8 PL/SQL
294
8.2 Struttura di un blocco PL/SQL anonimo
Un blocco PL/SQL anonimo suddiviso in tre aree delimitate dalle
quattro parole chiave DECLARE, BEGIN, EXCEPTION; END.
DECLARE
BEGIN
EXCEPTION
END;
295
indica ad Oracle di stampare in output il messaggio contenuto tra
parentesi.
Lo slash posto sotto la parola chiave END indica a SQL*Plus che deve
eseguire il programma. Per i comandi SQL avevamo visto che si potevano
indifferentemente utilizzare lo slash o il punto e virgola. In PL/SQL il punto e
virgola ha il significato di fine singola istruzione quindi per dire a SQL*Plus
di eseguire il programma si pu utilizzare solo lo slash. Lo slash ovviamente
non fa parte del programma PL/SQL.
296
Figura 8-2 Visualizzazione delloutput in SQL Developer.
In qualunque punto di un programma PL/SQL possibile inserire un
commento che sar ignorato da Oracle in due modi:
Includendo il commento tra i caratteri /* e */, in tal caso il
commento pu proseguire anche su pi righe.
Inserendo il commento dopo un doppio trattino --, in tal caso il
commento continua fino a fine riga.
Ad esempio:
DECLARE
A VARCHAR2(3); --Commento che continua fino a fine linea
BEGIN
/*commento che continua anche
Sulle righe successive
A quella in cui iniziato*/
dbms_output.put_line('Hello World!');
END;
298
8.3.3 Dichiarazione di costanti
Una costante unarea di memoria il cui contenuto non cambia nel
corso dellesecuzione del programma e che pu essere utilizzata nelle
istruzioni del programma con un nome simbolico.
Una costante in tutto identica ad una variabile a parte il fatto che nel
corso del programma non possibile modificarne il valore.
Nella dichiarazione si utilizza la parola chiave CONSTANT come
segue:
DECLARE
PI_GRECO CONSTANT NUMBER(3,2) := 3.14;
BEGIN
299
ELSE
<istruzioniN>
END IF;
END;
300
11 end if;
12 end;
13 /
A e B sono uguali
Procedura PL/SQL completata correttamente.
In questi esempi stato ignorato il caso in cui almeno una tra A e B sia
NULL. In tal caso valgono tutte le considerazioni fatte per lSQL: si possono
utilizzare le stesse funzioni per la gestione dei valori nulli e gli operatori di
confronto IS NULL ed IS NOT NULL.
La struttura condizionale CASE serve a decodificare un valore.
simile alla CASE di primo tipo vista in SQL:
DECLARE
<nome variabile> <tipo>;
BEGIN
<nome variabile> :=
CASE <dato da controllare>
WHEN <valore1> THEN
<valore di ritorno1>
WHEN <valore2> THEN
<valore di ritorno2>
...ALTRI BLOCCHI WHEN...
ELSE
<valore di ritornoN>
END;
END;
301
WTO >declare
2 voto number := 6;
3 giudizio varchar2(20);
4 begin
5 giudizio := case voto
6 when 10 then 'Eccellente'
7 when 9 then 'Ottimo'
8 when 8 then 'Distinto'
9 when 7 then 'Buono'
10 when 6 then 'Sufficiente'
11 when 5 then 'Mediocre'
12 else 'Insufficiente'
13 end;
14 dbms_output.put_line('Giudizio:'||giudizio);
15 end;
16 /
Giudizio:Sufficiente
WTO >declare
2 voto number := 3;
3 giudizio varchar2(20);
4 begin
5 giudizio := case voto
6 when 10 then 'Eccellente'
7 when 9 then 'Ottimo'
8 when 8 then 'Distinto'
9 when 7 then 'Buono'
10 when 6 then 'Sufficiente'
11 when 5 then 'Mediocre'
12 else 'Insufficiente'
13 end;
14 dbms_output.put_line('Giudizio:'||giudizio);
15 end;
16 /
Giudizio:Insufficiente
302
Quando Oracle incontra in un programma questa struttura esegue le
istruzioni1, poi testa la condizione, se questa vera salta alla fine del LOOP
e prosegue, se la condizione falsa esegue le istruzioni2 e ricomincia
eseguendo le istruzioni1. A questo punto verifica di nuovo la condizione e si
comporta come al giro precedente. Ovviamente la condizione ad un certo
punto deve diventare falsa, altrimenti si genera un ciclo infinito ed il
programma non finisce pi (almeno finch non consuma tutta la memoria o
determina qualche altro errore).
Come esempio scriviamo un programma che stampi tutti i numeri da
uno al giorno corrente del mese. Al momento della scrittura del programma
non si sa quanti numeri bisogna stampare, perch il programma potrebbe
girare un giorno qualsiasi.
Prima di tutto si dichiara una variabile numerica che inizializzata ad
uno. Nel corpo del programma c il LOOP, ad ogni iterazione si stampa il
valore della variabile e poi si controlla se tale valore ha raggiunto il giorno
corrente. Se la condizione vera si esce dal LOOP, altrimenti si incrementa
la variabile.
WTO >declare
2 g number:=1;
3 begin
4 loop
5 dbms_output.put_line('giorno '||g);
6 exit when g=extract(day from systimestamp);
7 g := g+1;
8 end loop;
9 end;
10 /
giorno 1
giorno 2
giorno 3
giorno 4
giorno 5
giorno 6
giorno 7
giorno 8
giorno 9
giorno 10
SYSDATE
---------
10-MAR-11
303
programmatori che hanno familiarit con altri linguaggi, Oracle ha introdotto
in PL/SQL altre due strutture iterative che sono casi particolari del LOOP
appena presentato. Si tratta del FOR e del WHILE.
Il ciclo FOR si applica quando la condizione di uscita di un tipo
particolare: una variabile si incrementa fino a raggiungere un determinato
valore. proprio il caso visto nellesempio precedente. La struttura FOR
assume la sintassi seguente:
FOR <variabile> IN <valore1>..<valore2> LOOP
<istruzioni>
END LOOP;
304
La struttura FOR molto utilizzata perch semplifica la
programmazione non richiedendo la dichiarazione, linizializzazione e
lincremento espliciti della variabile di ciclo.
Il ciclo WHILE si applica a qualunque condizione ma tale condizione
controllata ad inizio ciclo, prima dellesecuzione delle istruzioni operative. La
sintassi della struttura :
WHILE <condizione> LOOP
<istruzioni>
END LOOP;
305
7 end if;
8 oggi := 0;
9 <<salta_qui>>
10 dbms_output.put_line('giorno dopo il salto '||oggi);
11 end;
12 /
giorno 17
giorno dopo il salto 17
Quindi Oracle non entra nellIF e non effettua il salto. Viene eseguito
lazzeramento della variabile OGGI che, dunque, alla seconda stampa vale
zero.
La struttura GOTO diffusamente considerata il nemico pubblico
numero uno della buona programmazione. In effetti, questa struttura invita il
programmatore a fare salti incontrollati e se ne pu tranquillamente fare a
meno. per importante sottolineare che si pu facilmente scrivere un buon
programma usando le GOTO e si pu altrettanto facilmente scrivere un
pessimo programma senza utilizzare questa struttura.
Listruzione NULL non esegue nessuna operazione. In alcuni casi
Oracle richiede necessariamente che in una struttura ci sia unistruzione. Ad
esempio non possibile scrivere unIF senza istruzioni al proprio interno:
WTO >begin
2 if 1>2 then
3 end if;
4 end;
5 /
end if;
*
ERRORE alla riga 3:
ORA-06550: line 3, column 2:
306
PLS-00103: Encountered the symbol "END" when expecting one of the
following:
begin case declare exit for goto if loop mod null pragma
raise return select update while with <an identifier>
<a double-quoted delimited-identifier> <a bind variable> <<
close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe
COUNT(*)
----------
8
308
PLS-00103: Encountered the symbol "CREATE" when expecting one of the
following:
begin case declare exit for goto if loop mod null pragma
raise return select update while with <an identifier>
<a double-quoted delimited-identifier> <a bind variable> <<
close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe
309
WTO >declare
2 num_r number;
3 s varchar2(100):=
4 'select count(*) from clienti where comune=:c';
5 begin
6 execute immediate s into num_r using 'H501';
7 dbms_output.put_line('Ho '||num_r||' clienti a ROMA.');
8 execute immediate s into num_r using 'F839';
9 dbms_output.put_line('Ho '||num_r||' clienti a NAPOLI.');
10 end;
11 /
Ho 2 clienti a ROMA.
Ho 2 clienti a NAPOLI.
310
I due programmi sono equivalenti. Proviamo solo per un momento a
rinominare la tabella FATTURE in FATTURE_NEW.
WTO >rename fatture to fatture_new;
Tabella rinominata.
311
8.5.3 CURSORI
Gli esempi di query SQL visti finora, sia nella modalit statica che nella
modalit dinamica, estraggono un singolo record dal database. Nel caso in
cui la query estragga un insieme di record la clausola INTO genera un errore.
Chiaramente spesso necessario leggere molti record dal DB, per gestire
questesigenza il PL/SQL mette a disposizione i cursori. Un cursore non
altro che un nome simbolico assegnato ad una query. Il cursore si dichiara
nella sezione DECLARE e poi si utilizza (eseguendo effettivamente la query
e scorrendo le righe estratte) nella sezione delle istruzioni operative.
Lo scorrimento di un cursore richiede un LOOP, non essendo noto a
priori quanti record ci saranno nel cursore.
Nellesempio seguente viene dichiarato un cursore che estrae nome,
cognome e comune dei clienti, il cursore viene poi aperto (cio viene
eseguita la query), scorso ed infine chiuso. Solo i clienti residenti a Napoli o
Roma vengono stampati a video.
WTO >declare
2 v_nome clienti.nome%type;
3 v_cogn clienti.cognome%type;
4 v_com clienti.comune%type;
5 cursor c is
6 select nome, cognome, comune
7 from clienti;
8 begin
9 open c;
10 loop
11 fetch c into v_nome, v_cogn, v_com;
12 exit when c%notfound;
13 if v_com in ('H501','F839') then
14 dbms_output.put_line('Cliente '||v_nome||' '||v_cogn);
15 end if;
16 end loop;
17 close c;
18 end;
19 /
Cliente MARCO ROSSI
Cliente GIOVANNI BIANCHI
Cliente GENNARO ESPOSITO
Cliente PASQUALE RUSSO
312
Il comando CLOSE chiude il cursore liberando la memoria ad esso
associata.
Oltre allattributo %NOTFOUND ce ne sono un paio particolarmente
utili. Lattributo %ISOPEN restituisce TRUE se il cursore stato gi aperto e
FALSE se non stato ancora aperto. Serve a prevenire il rischio di chiudere
un cursore che non mai stato aperto evitando cos un errore.
Ipotizziamo, infatti, di scrivere un semplice programma in cui si chiude
un cursore mai aperto.
WTO >declare
2 cursor c is select sysdate from dual;
3 begin
4 if 1>2 then
5 open c;
6 end if;
7 close c;
8 end;
9 /
declare
*
ERRORE alla riga 1:
ORA-01001: invalid cursor
ORA-06512: at line 7
313
WTO >declare
2 v_nome clienti.nome%type;
3 v_cogn clienti.cognome%type;
4 v_com clienti.comune%type;
5 cursor c is
6 select nome, cognome, comune
7 from clienti;
8 begin
9 open c;
10 loop
11 fetch c into v_nome, v_cogn, v_com;
12 exit when c%notfound;
13 dbms_output.put_line('Letta la riga '||c%rowcount);
14 if v_com in ('H501','F839') then
15 dbms_output.put_line('Cliente '||v_nome||' '||v_cogn);
16 end if;
17 end loop;
18 close c;
19 end;
20 /
Letta la riga 1
Cliente MARCO ROSSI
Letta la riga 2
Cliente GIOVANNI BIANCHI
Letta la riga 3
Letta la riga 4
Letta la riga 5
Letta la riga 6
Cliente GENNARO ESPOSITO
Letta la riga 7
Cliente PASQUALE RUSSO
Letta la riga 8
314
11 end loop;
12 end;
13 /
Letta la riga 1
Cliente MARCO ROSSI
Letta la riga 2
Cliente GIOVANNI BIANCHI
Letta la riga 3
Letta la riga 4
Letta la riga 5
Letta la riga 6
Cliente GENNARO ESPOSITO
Letta la riga 7
Cliente PASQUALE RUSSO
Letta la riga 8
315
WTO >declare
2 a number;
3 begin
4 a := 1/0;
5 dbms_output.put_line('A='||a);
6 exception
7 when zero_divide then
8 dbms_output.put_line('Divisione per zero non ammessa.');
9 end;
10 /
Divisione per zero non ammessa.
316
Il programma seguente cerca di aggiornare il codice cliente otto a
sette, causando una duplicazione di valore e dunque un errore.
WTO >begin
2 update clienti
3 set cod_cliente=7
4 where cod_cliente=8;
5 end;
6 /
begin
*
ERRORE alla riga 1:
ORA-00001: unique constraint (WTO_ESEMPIO.CLI_PK) violated
ORA-06512: at line 2
INVALID_NUMBER
Si verifica nel caso in cui viene effettuata una conversione di una
stringa a numero e la stringa non contiene un numero valido.
Nellesempio seguente si cerca di convertire il codice fiscale dei clienti
in numero.
WTO >declare
2 a number;
3 begin
4 select to_number(cod_fisc)
5 into a
6 from clienti;
7 end;
8 /
declare
*
ERRORE alla riga 1:
ORA-01722: invalid number
ORA-06512: at line 4
WTO >declare
2 a number;
3 begin
4 select to_number(cod_fisc)
5 into a
6 from clienti;
7 exception
8 when invalid_number then
9 dbms_output.put_line('Numero non valido.');
317
10 end;
11 /
Numero non valido.
NO_DATA_FOUND
Si verifica quando una SELECT..INTO non estrae nessun record.
WTO >declare
2 a number;
3 begin
4 select cod_cliente
5 into a
6 from clienti
7 where nome='ASTOLFO';
8 end;
9 /
declare
*
ERRORE alla riga 1:
ORA-01403: no data found
ORA-06512: at line 4
WTO >declare
2 a number;
3 begin
4 select cod_cliente
5 into a
6 from clienti
7 where nome='ASTOLFO';
8 exception
9 when no_data_found then
10 dbms_output.put_line('Cliente non trovato.');
11 end;
12 /
Cliente non trovato.
TOO_MANY_ROWS
Si verifica quando una SELECT..INTO estrae pi di un record.
WTO >declare
2 a number;
3 begin
4 select cod_cliente
5 into a
6 from clienti
7 where comune='H501';
8 end;
9 /
declare
*
ERRORE alla riga 1:
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at line 4
318
WTO >declare
2 a number;
3 begin
4 select cod_cliente
5 into a
6 from clienti
7 where comune='H501';
8 exception
9 when too_many_rows then
10 dbms_output.put_line('Pi di un cliente estratto.');
11 end;
12 /
Pi di un cliente estratto.
VALUE_ERROR
Si verifica quando si mette in una variabile un valore non valido.
Nellesempio seguente si cerca di assegnare il numero 5000 ad una variabile
definita NUMBER(3).
WTO >declare
2 a number(3);
3 begin
4 a:= 5000;
5 end;
6 /
declare
*
ERRORE alla riga 1:
ORA-06502: PL/SQL: numeric or value error: number precision too large
ORA-06512: at line 4
WTO >declare
2 a number(3);
3 begin
4 a:= 5000;
5 exception
6 when value_error then
7 dbms_output.put_line('Valore non valido.');
8 end;
9 /
Valore non valido.
ZERO_DIVIDE
Si verifica quando si cerca di effettuare una divisione per zero. Alcuni
esempi sono stati mostrati nel paragrafo precedente.
OTHERS
uneccezione generica che si utilizza con il significato qualunque
altro errore si verifichi. Nellesempio seguente il programma gestisce gli
errori NO_DATA_FOUND e TOO_MANY_ROWS ma quello che si verifica
INVALID_NUMBER che non esplicitamente gestito. Il flusso finisce dunque
nel WHEN OTHERS dove c un messaggio generico.
319
WTO >declare
2 a number;
3 begin
4 select to_number(cod_fisc)
5 into a
6 from clienti
7 where cod_cliente=1;
8 exception
9 when no_data_found then
10 dbms_output.put_line('Cliente non trovato.');
11 when too_many_rows then
12 dbms_output.put_line('Pi di un cliente estratto.');
13 when others then
14 dbms_output.put_line('Errore generico.');
15 end;
16 /
Errore generico.
321
Nellesempio seguente lerrore definito dallutente gestito mediante
WHEN OTHERS. Le funzioni SQLCODE e SQLERRM sono state utilizzate
per mostrare quale errore si verifica.
WTO >begin
2 raise_application_error(-20123,'Errore utente.');
3 exception
4 when others then
5 dbms_output.put_line('Errore generico.');
6 dbms_output.put_line('Codice='||sqlcode);
7 dbms_output.put_line(sqlerrm);
8 end;
9 /
Errore generico.
Codice=-20123
ORA-20123: Errore utente.
322
Procedura PL/SQL completata correttamente.
323
3 begin
4 for i in 1..20 loop
5 dbms_output.put_line('I='||i);
6 a:=1/(i-7);
7 dbms_output.put_line('A='||a);
8 end loop;
9 exception
10 when zero_divide then
11 dbms_output.put_line('Divisione per zero!');
12 end;
13 /
I=1
A=-,17
I=2
A=-,2
I=3
A=-,25
I=4
A=-,33
I=5
A=-,5
I=6
A=-1
I=7
Divisione per zero!
324
Divisione per zero!
I=8
A=1
I=9
A=,5
I=10
A=,33
I=11
A=,25
I=12
A=,2
I=13
A=,17
I=14
A=,14
I=15
A=,13
I=16
A=,11
I=17
A=,1
I=18
A=,09
I=19
A=,08
I=20
A=,08
325
16 end;
17 /
Gestore interno
Siamo nel blocco esterno
326
Riprendiamo un esempio utilizzato in precedenza per mostrare il
funzionamento della SELECT..INTO.
WTO >declare
2 num_f number;
3 max_f number;
4 avg_f number;
5 begin
6 select count(*), max(importo), avg(importo)
7 into num_f, max_f, avg_f
8 from fatture;
9
10 dbms_output.put_line('Ci sono '||num_f||' fatture.');
11 dbms_output.put_line('La pi alta di '||max_f||' euro');
12 dbms_output.put_line('La media di '||avg_f||' euro');
13
14 end;
15 /
Ci sono 5 fatture.
La pi alta di 1000 euro
La media di 600 euro
327
tabella>%ROWTYPE, risparmiando cos di indicare tutte le singole colonne
ed i relativi tipi.
Nellesempio seguente si leggono tutte le colonne della tabella
CLIENTI per una specifica riga e poi si stampano solo due campi.
WTO >declare
2 r clienti%rowtype;
3 begin
4 select *
5 into r
6 from clienti
7 where cod_cliente=3;
8
9 dbms_output.put_line('Nome='||r.nome);
10 dbms_output.put_line('Cognome='||r.cognome);
11
12 end;
13 /
Nome=MATTEO
Cognome=VERDI
328
7 if r.comune in ('H501','F839') then
8 dbms_output.put_line('Cliente '||r.nome||' '||r.cognome);
9 end if;
10 end loop;
11 end;
12 /
Letta la riga 1
Cliente MARCO ROSSI
Letta la riga 2
Cliente GIOVANNI BIANCHI
Letta la riga 3
Letta la riga 4
Letta la riga 5
Letta la riga 6
Cliente GENNARO ESPOSITO
Letta la riga 7
Cliente PASQUALE RUSSO
Letta la riga 8
329
Il cliente 8 VINCENZO
Indica che il tipo T_CLIENTI una lista di coppie (chiave, valore) in cui
la chiave un intero ed il valore un VARCHAR2(30).
Il tipo BINARY_INTEGER un tipo predefinito di PL/SQL.
Successivamente il tipo T_CLIENTI utilizzato per dichiarare una
variabile di tipo lista, inizialmente vuota.
La sintassi utilizzata per il CURSOR FOR LOOP evita al
programmatore di esplicitare la dichiarazione del cursore. Il cursore
implicitamente definito nel FOR scrivendone la SELECT tra parentesi.
Il popolamento della lista CLI fatto utilizzando un LOOP sugli
elementi estratti dalla query. Per ogni record si definisce un nuovo elemento
della lista avente come indice R.COD_CLIENTE e come valore R.NOME.
La stampa di tutti i valori dellarray si effettua mediante un ciclo che fa
uso di tre funzioni di base che tutti gli array associativi mettono a
disposizione.
CLI.FIRST restituisce la chiave di valore pi basso presente nella lista.
CLI.NEXT(I) restituisce la chiave successiva a quella che riceve in
input.
CLI.LAST restituisce la chiave di valore pi alto presente nella lista.
Il valore di un array associativo pu essere un record. In tal caso
larray una vera e propria tabella in memoria.
Nellesempio seguente si ripete quanto fatto nellultimo esempio ma si
mette nellarray lintero contenuto della tabella clienti.
WTO >declare
2 type t_clienti is table of clienti%rowtype
3 index by binary_integer;
4 cli t_clienti;
5 i number;
6 begin
7 for r in (select * from clienti) loop
8 cli(r.cod_cliente) := r;
9 end loop;
10
11 i := cli.first;
12 loop
13 dbms_output.put_line('Il cliente '||i||' '||cli(i).nome);
14 dbms_output.put_line('il suo cf '||cli(i).cod_fisc);
15 dbms_output.put_line('----------------------------------');
16 exit when i=cli.last;
17 i:=cli.next(i);
18 end loop;
19 end;
330
20 /
331
Il cliente 1 MARCO
il suo cf RSSMRC70R20H501X
----------------------------------
Il cliente 2 GIOVANNI
il suo cf
----------------------------------
Il cliente 3 MATTEO
il suo cf VRDMTT69S02H501X
----------------------------------
Il cliente 4 LUCA
il suo cf NRILCU77A22F205X
----------------------------------
Il cliente 5 AMBROGIO
il suo cf
----------------------------------
Il cliente 6 GENNARO
il suo cf SPSGNN71B10F839X
----------------------------------
Il cliente 7 PASQUALE
il suo cf RSSPSQ70C14F839X
----------------------------------
Il cliente 8 VINCENZO
il suo cf
----------------------------------
332
ANNO 2000 2001 2002 2003 2004
CITTA
Roma 13.000 11.300 12.500 14.400 16.000
Napoli 5.400 6.500 6.200 5.800 6.100
Milano 11.300 13.100 12.600 15.700 14.700
Firenze 2.350 2.680 2.200 2.920 2.810
Bologna 1.350 1.470 1.840 1.930 1.150
8.7.3 Varray
Un varray, o array a dimensione variabile, una lista di coppie (chiave,
valore) avente un numero di elementi massimo definito ed un indice sempre
numerico.
333
Il massimo numero di coppie presenti nellarray si definisce in fase di
dichiarazione utilizzando la sintassi seguente:
TYPE <nome tipo> is VARRAY(<dimensione massima>) of <tipo>
334
8.7.4 Nested Table
Una NESTED TABLE (tabella innestata) una lista di valori non
ordinati di un determinato tipo.
Per definire una Nested Table si utilizza la sintassi
TYPE <nome tipo> is TABLE of <tipo>
335
8.7.5 Bulk collect
Array associativi, Varray e Nested tables prendono il nome generico di
COLLECTION.
C un modo per semplificare il popolamento di una COLLECTION
sulla base dei dati estratti con una query. Anzich utilizzare un ciclo, come
fatto negli esempi precedenti, possibile usare la clausola BULK COLLECT
della SELECT..INTO.
Riprendiamo uno dei primi esempi e modifichiamolo con la clausola
BULK COLLECT
WTO >declare
2 type t_clienti is table of clienti%rowtype
3 index by binary_integer;
4 cli t_clienti;
5 i number;
6 begin
7 select *
8 bulk collect into cli
9 from clienti;
10
11 i := cli.first;
12 loop
13 dbms_output.put_line('Il cliente '||i||' '||cli(i).nome);
14 dbms_output.put_line('il suo cf '||cli(i).cod_fisc);
15 dbms_output.put_line('----------------------------------');
16 exit when i=cli.last;
17 i:=cli.next(i);
18 end loop;
19 end;
20 /
Il cliente 1 MARCO
il suo cf RSSMRC70R20H501X
----------------------------------
Il cliente 2 GIOVANNI
il suo cf
----------------------------------
Il cliente 3 MATTEO
il suo cf VRDMTT69S02H501X
----------------------------------
Il cliente 4 LUCA
il suo cf NRILCU77A22F205X
----------------------------------
Il cliente 5 AMBROGIO
il suo cf
----------------------------------
Il cliente 6 GENNARO
il suo cf SPSGNN71B10F839X
----------------------------------
Il cliente 7 PASQUALE
il suo cf RSSPSQ70C14F839X
----------------------------------
Il cliente 8 VINCENZO
il suo cf
----------------------------------
336
La sintassi semplicissima, si tratta di aggiungere la clausola BULK
COLLECT prima della INTO e fornire, ovviamente, una o pi collection in cui
inserire i dati.
TRIM
Riceve in input un numero intero ed elimina dalla coda della collection
un numero di elementi pari al numero ricevuto in input.
WTO >declare
2 type t_citta is table of varchar2(30);
3 c t_citta := t_citta('ROMA','NAPOLI','MILANO', 'FIRENZE');
338
4 i number;
5 begin
6 i := c.first;
7 loop
8 dbms_output.put_line('Citt '||i||': '||c(i));
9 exit when i = c.last;
10 i := c.next(i);
11 end loop;
12 dbms_output.put_line('Elimino gli ultimi due elementi.');
13 c.trim(2);
14 i := c.first;
15 loop
16 dbms_output.put_line('Citt '||i||': '||c(i));
17 exit when i = c.last;
18 i := c.next(i);
19 end loop;
20 end;
21 /
Citt 1: ROMA
Citt 2: NAPOLI
Citt 3: MILANO
Citt 4: FIRENZE
Elimino gli ultimi due elementi.
Citt 1: ROMA
Citt 2: NAPOLI
339
Citt 2: NAPOLI
Citt 3: MILANO
Citt 4: FIRENZE
Citt 5:
EXISTS
Ritorna TRUE o FALSE in funzione del fatto che un elemento con un
determinato indice esiste o meno nella collezione.
WTO >declare
2 type t_citta is table of varchar2(30);
3 c t_citta := t_citta('ROMA','NAPOLI','MILANO', 'FIRENZE');
4 i number;
5 begin
6 i := c.first;
7 loop
8 dbms_output.put_line('Citt '||i||': '||c(i));
9 exit when i = c.last;
10 i := c.next(i);
11 end loop;
12 dbms_output.put_line('Esiste l''elemento 3?');
340
13 if c.exists(3) then
14 dbms_output.put_line('S, esiste.');
15 else
16 dbms_output.put_line('No, non esiste.');
17 end if;
18 dbms_output.put_line('Esiste l''elemento 5?');
19 if c.exists(5) then
20 dbms_output.put_line('S, esiste.');
21 else
22 dbms_output.put_line('No, non esiste.');
23 end if;
24 end;
25 /
Citt 1: ROMA
Citt 2: NAPOLI
Citt 3: MILANO
Citt 4: FIRENZE
Esiste l'elemento 3?
S, esiste.
Esiste l'elemento 5?
No, non esiste.
FIRST
Il metodo FIRST ritorna il primo indice della collezione.
WTO >declare
2 type t_citta is table of varchar2(30);
3 c t_citta := t_citta('ROMA','NAPOLI','MILANO', 'FIRENZE');
4 i number;
5 begin
6 i := c.first;
7 loop
8 dbms_output.put_line('Citt '||i||': '||c(i));
9 exit when i = c.last;
10 i := c.next(i);
11 end loop;
12 dbms_output.put_line('Primo indice='||c.first);
13 end;
14 /
Citt 1: ROMA
Citt 2: NAPOLI
Citt 3: MILANO
Citt 4: FIRENZE
Primo indice=1
LAST
Il metodo LAST ritorna lultimo indice della collezione.
WTO >declare
2 type t_citta is table of varchar2(30);
3 c t_citta := t_citta('ROMA','NAPOLI','MILANO', 'FIRENZE');
4 i number;
5 begin
6 i := c.first;
7 loop
8 dbms_output.put_line('Citt '||i||': '||c(i));
9 exit when i = c.last;
341
10 i := c.next(i);
11 end loop;
12 dbms_output.put_line('Ultimo indice='||c.last);
13 end;
14 /
Citt 1: ROMA
Citt 2: NAPOLI
Citt 3: MILANO
Citt 4: FIRENZE
Ultimo indice=4
COUNT
Il metodo COUNT ritorna il numero totale di elementi presenti nella
collezione.
WTO >declare
2 type t_citta is table of varchar2(30);
3 c t_citta := t_citta('ROMA','NAPOLI','MILANO', 'FIRENZE');
4 i number;
5 begin
6 i := c.first;
7 loop
8 dbms_output.put_line('Citt '||i||': '||c(i));
9 exit when i = c.last;
10 i := c.next(i);
11 end loop;
12 dbms_output.put_line('Numero di elementi='||c.count);
13 end;
14 /
Citt 1: ROMA
Citt 2: NAPOLI
Citt 3: MILANO
Citt 4: FIRENZE
Numero di elementi=4
LIMIT
Il metodo LIMIT restituisce il numero massimo di elementi che la
collezione pu contenere. Restituisce NULL se la collezione non ha un
numero massimo di elementi. In un array associativo ed in una nested table
sar sempre NULL.
WTO >declare
2 type t_citta is table of varchar2(30);
3 c t_citta := t_citta('ROMA','NAPOLI','MILANO', 'FIRENZE');
4 i number;
5 begin
6 i := c.first;
7 loop
8 dbms_output.put_line('Citt '||i||': '||c(i));
9 exit when i = c.last;
10 i := c.next(i);
11 end loop;
12 dbms_output.put_line('Numero massimo di elementi='||c.limit);
13 end;
14 /
Citt 1: ROMA
342
Citt 2: NAPOLI
Citt 3: MILANO
Citt 4: FIRENZE
Numero massimo di elementi=
PRIOR
Il metodo PRIOR restituisce lindice precedente rispetto a quello che
riceve in input.
WTO >declare
2 type t_citta is table of varchar2(30);
3 c t_citta := t_citta('ROMA','NAPOLI','MILANO', 'FIRENZE');
4 i number;
5 begin
6 i := c.first;
7 loop
8 dbms_output.put_line('Citt '||i||': '||c(i));
9 exit when i = c.last;
10 i := c.next(i);
11 end loop;
12 dbms_output.put_line('Precedente di 3='||c.prior(3));
13 c.delete(2);
14 dbms_output.put_line('Precedente di 3='||c.prior(3));
15 end;
16 /
Citt 1: ROMA
Citt 2: NAPOLI
Citt 3: MILANO
Citt 4: FIRENZE
Precedente di 3=2
Precedente di 3=1
NEXT
Il metodo NEXT restituisce lindice successivo rispetto a quello
ricevuto in input.
WTO >declare
2 type t_citta is table of varchar2(30);
343
3 c t_citta := t_citta('ROMA','NAPOLI','MILANO', 'FIRENZE');
4 i number;
5 begin
6 i := c.first;
7 loop
8 dbms_output.put_line('Citt '||i||': '||c(i));
9 exit when i = c.last;
10 i := c.next(i);
11 end loop;
12 dbms_output.put_line('Successivo di 2='||c.next(2));
13 end;
14 /
Citt 1: ROMA
Citt 2: NAPOLI
Citt 3: MILANO
Citt 4: FIRENZE
Successivo di 2=3
8.8.1 Procedure
Una procedura PL/SQL (in inglese Stored Procedure) un programma
PL/SQL memorizzato nel database che accetta un determinato numero di
parametri di input/output ed esegue unattivit nel database senza ritornare
un valore al programma che lha chiamato.
La sintassi per la definizione di una procedura la seguente:
CREATE OR REPLACE PROCEDURE <nome procedura>
(<nome parametro1> <modo parametro1> <tipo parametro1>,
<nome parametro2> <modo parametro2> <tipo parametro2>,
...
<nome parametroN> <modo parametroN> <tipo parametroN>) IS
<dichiarazione delle variabili>
BEGIN
<corpo PL/SQL della procedura>
END;
Procedura creata.
LINE/COL ERROR
-------- ---------------------------------------------------
3/3 PL/SQL: SQL Statement ignored
3/10 PL/SQL: ORA-00942: table or view does not exist
Il log degli errori letto dal basso verso lalto mostra che a linea 3 della
procedura stato utilizzata una tabella di database inesistente e per questo
motivo lintera istruzione a linea 3 stata ignorata.
Corretto lerrore creiamo nuovamente la procedura e cerchiamo di
eseguirla.
WTO >create or replace procedure aumenta is
2 begin
3 update fatture
4 set importo = importo*1.1;
5 end;
6 /
Procedura creata.
Rollback completato.
Procedura creata.
347
Procedura PL/SQL completata correttamente.
Annullo le modifiche.
WTO >rollback;
Rollback completato.
*
ERRORE alla riga 1:
ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'AUMENTA'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
348
C, per, la possibilit di assegnare ai parametri un valore di default in
modo che il chiamante possa decidere se valorizzarli o no.
WTO >create or replace procedure aumenta
2 (pct in number default 10) is
3 begin
4 update fatture
5 set importo=importo*(1+pct/100);
6 end;
7 /
Procedura creata.
WTO >rollback;
349
Rollback completato.
Procedura creata.
350
Massimo importo=1100
MAXIMP
----------
1210
Rollback completato.
8.8.2 Funzioni
Una funzione PL/SQL si comporta come una procedura con la sola
differenza che deve restituire un valore al termine dellesecuzione. La parola
chiave RETURN consente, ad inizio funzione, di dichiarare che tipo di dato
sar ritornato e, nel corpo della funzione, di determinare il valore da
restituire.
La sintassi di una funzione si presenta come segue:
CREATE OR REPLACE FUNCTION <nome funzione>
(<nome parametro1> <modo parametro1> <tipo parametro1>,
<nome parametro2> <modo parametro2> <tipo parametro2>,
...
<nome parametroN> <modo parametroN> <tipo parametroN>)
RETURN <tipo> IS
<dichiarazione delle variabili>
BEGIN
<corpo PL/SQL della funzione>
RETURN <valore>;
END;
LINE/COL ERROR
-------- --------------------------------------------------------
352
1/20 PLS-00103: Encountered the symbol "IS" when expecting one of
the following:
( return compress compiled wrapped
Funzione creata.
Funzione creata.
TEST_FUNC(200) TEST_FUNC(15)
-------------- -------------
200 150
353
7 else
8 ret_val := mypar*10;
9 end if;
10
11 return ret_val;
12 end;
13 /
Funzione creata.
TEST_FUNC(200) TEST_FUNC(15)
-------------- -------------
200 150
Anche una funzione che prevede la clausola RETURN pu, per errore,
terminare senza valore. Nellesempio seguente si gestisce leccezione
VALUE_ERROR che si potrebbe verificare nelle assegnazioni:
WTO >create or replace function test_func (
2 mypar in number) return number is
3 ret_val number(3);
4 begin
5 if mypar >100 then
6 ret_val := mypar;
7 else
8 ret_val := mypar*10;
9 end if;
10
11 return ret_val;
12 exception
13 when value_error then
14 dbms_output.put_line('Errore di valore.');
15 end;
16 /
Funzione creata.
TEST_FUNC(200) TEST_FUNC(15)
-------------- -------------
200 150
Errore di valore.
354
Lassegnazione a linea 6 ha generato un VALUE_ERROR perch
cercava di mettere il valore 1000 in una variabile definita NUMBER(3), il
flusso del programma quindi saltato al blocco EXCEPTION dove era
previsto un messaggio derrore ma non c la clausola RETURN. Oracle
quindi stampa il messaggio derrore e lerrore dovuto al fatto che la funzione
finita senza un valore di ritorno.
Per ovviare a questo problema si pu ridefinire la funzione in questo
modo:
WTO >create or replace function test_func (
2 mypar in number) return number is
3 ret_val number(3);
4 begin
5 if mypar >100 then
6 ret_val := mypar;
7 else
8 ret_val := mypar*10;
9 end if;
10
11 return ret_val;
12 exception
13 when value_error then
14 dbms_output.put_line('Errore di valore.');
15 return null;
16 end;
17 /
Funzione creata.
TEST_FUNC(1000)
---------------
Errore di valore.
Funzione creata.
355
WTO >select test_func(200), test_func(15)
2 from dual;
TEST_FUNC(200) TEST_FUNC(15)
-------------- -------------
200 150
TEST_FUNC(1000)
---------------
Errore di valore.
Funzione creata.
Funzione creata.
RET_VAL
----------
500
8.8.3 Package
Un package PL/SQL un oggetto virtuale che racchiude un insieme di
procedure e funzioni. Ci sono vari buoni motivi per accorpare le procedure e
funzioni in package anzich tenerle slegate tra loro:
Modularit dellapplicazione: le procedure e funzioni logicamente
collegate tra loro sono conservate nello stesso package e viste
come un tuttuno. Ci agevola un buon disegno architetturale della
soluzione consentendo di avere pochi pacchetti di programmi
anzich molti programmi sciolti.
Possibilit di nascondere le funzionalit di servizio: un package
composto di due parti, la specification ed il body. Solo le
procedure, funzioni e variabili incluse nella specification possono
essere accedute dagli altri programmi PL/SQL presenti nel DB; le
procedure, funzioni e variabili presenti solo nel body sono private
ed accessibili solo dagli altri programmi del package.
357
Variabili di sessione: una variabile definita nel package al di fuori di
tutte le procedure e funzioni istanziata la prima volta che il
package viene richiamato e resta valida fino a fine sessione.
dunque possibile utilizzare delle variabili che sopravvivono alla fine
del programma e possono essere utilizzate da altri programmi che
gireranno in seguito nella stessa sessione.
La sintassi per la creazione di un package, come detto, tale da
definire due oggetti separati: la specification ed il body.
Per la specification:
CREATE OR REPLACE PACKAGE <nome package> IS
PROCEDURE/FUNCTION <nome procedura o funzione >
<parametri> <eventuale clausola return>;
PROCEDURE/FUNCTION <nome procedura o funzione >
<parametri> <eventuale clausola return>;
..
PROCEDURE/FUNCTION <nome procedura o funzione >
<parametri> <eventuale clausola return>;
<dichiarazione delle variabili di package>
END;
Per il body
CREATE OR REPLACE PACKAGE BODY <nome package> IS
<dichiarazione delle variabili private di package>
PROCEDURE/FUNCTION <nome procedura o funzione >
<parametri> <eventuale clausola return> IS
<variabili di procedura o funzione>
BEGIN
<corpo della procedura o funzione>
END;
Procedura eliminata.
Package creato.
359
Procedura PL/SQL completata correttamente.
WTO >print m
M
----------
1200
TEST_PKG.TEST_FUNC(15)
----------------------
150
WTO >rollback;
Rollback completato.
Package creato.
WTO >print m
M
----------
1200
WTO >print m
M
----------
100
361
12
13 function test_func (mypar in number) return number is
14 ret_val number(3);
15 begin
16 if mypar >100 then
17 ret_val := mypar;
18 else
19 ret_val := mypar*10;
20 end if;
21
22 return ret_val;
23 exception
24 when value_error then
25 dbms_output.put_line('Errore di valore.');
26 return null;
27 end;
28
29 end;
30 /
LINE/COL ERROR
-------- --------------------------------------------------------
9/3 PL/SQL: Statement ignored
9/14 PLS-00313: 'TEST_FUNC' not declared in this scope
362
27 max_imp := test_func(10);
28
29 end;
30
31 end;
32 /
WTO >print m
M
----------
100
WTO >print m
M
----------
1234
364
8.8.4 Database Trigger
Un database trigger un programma PL/SQL salvato nel database
che scatta automaticamente quando si verifica un determinato evento. I
trigger si dividono in due categorie:
I system trigger sono collegati ad eventi DDL (ad esempio DROP,
CREATE, ALTER) oppure ad eventi amministrativi (ad esempio STARTUP,
SHUTDOWN) che avvengono in un determinato schema oppure sullintero
database. Sono utilizzati prevalentemente per attivit di amministrazione del
database e per questo motivo non saranno approfonditi in questo manuale.
I DML trigger sono collegati ad eventi di tipo DML (INSERT, UPDATE
o DELETE) su una specifica tabella o vista. Nel seguito si approfondiranno
solo i trigger di questa categoria.
Come detto, levento che pu far scattare un trigger lesecuzione di
un comando DML su una tabella (o vista). Il trigger pu essere configurato
per scattare prima o dopo lesecuzione del comando DML.
La sintassi minimale per la definizione di un trigger
CREATE OR REPLACE TRIGGER <nome trigger>
<BEFORE/AFTER> <INSERT/UPDATE/DELETE> ON <nome tabella>
DECLARE
<eventuali vairabili e costanti>
BEGIN
<codice PL/SQL del trigger>
END;
Trigger creato.
Aggiornate 8 righe.
WTO >rollback;
Completato rollback.
365
record, lo statement trigger scatterebbe una sola volta mentre lEACH ROW
trigger scatta cento volte.
Per definire un EACH ROW trigger basta aggiungere la clausola FOR
EACH ROW.
WTO >create or replace trigger TEST_UPD_CLI
2 AFTER UPDATE ON CLIENTI
3 FOR EACH ROW
4 begin
5 dbms_output.put_line('Trigger eseguito!');
6 end;
7 /
Trigger creato.
Aggiornate 8 righe.
WTO >rollback;
Completato rollback.
Trigger creato.
366
WTO >update clienti set nome='pippo';
Aggiornate 8 righe.
WTO >update clienti set nome='Pippo';
Trigger eseguito!
Trigger eseguito!
Trigger eseguito!
Trigger eseguito!
Trigger eseguito!
Trigger eseguito!
Trigger eseguito!
Trigger eseguito!
Aggiornate 8 righe.
WTO >rollback;
Rollback completato.
Nel primo UPDATE il trigger non scattato perch il nuovo nome del
cliente cominciava per p minuscola, nel secondo update invece il nuovo
nome del cliente comincia per P maiuscola ed il trigger scatta.
REFERENZIARE LE COLONNE
Allinterno del corpo del trigger, in caso FOR EACH ROW, possibile
referenziare i valori delle colonne del record. Per ogni colonna della tabella
esistono due valori :OLD.<nome colonna> e :NEW.<nome colonna> che
rappresentano il valore di quella colonna prima e dopo listruzione DML che
fa scattare il trigger. Per capire meglio il funzionamento dei prefissi OLD e
NEW si consideri lesempio seguente.
WTO >create or replace trigger TEST_UPD_CLI
2 AFTER UPDATE ON CLIENTI
3 FOR EACH ROW
4 WHEN (new.NOME like 'P%')
5 begin
6 dbms_output.put_line('Cliente '||:old.cod_cliente||
7 ' vecchio nome '||:old.nome||' nuovo '||:new.nome);
8 end;
9 /
Trigger creato.
WTO >update clienti set nome='Pippo';
Cliente 1 vecchio nome MARCO nuovo Pippo
Cliente 2 vecchio nome GIOVANNI nuovo Pippo
Cliente 3 vecchio nome MATTEO nuovo Pippo
Cliente 4 vecchio nome LUCA nuovo Pippo
Cliente 5 vecchio nome AMBROGIO nuovo Pippo
Cliente 6 vecchio nome GENNARO nuovo Pippo
Cliente 7 vecchio nome PASQUALE nuovo Pippo
Cliente 8 vecchio nome VINCENZO nuovo Pippo
Aggiornate 8 righe.
WTO >rollback;
Rollback completato.
367
In un trigger di UPDATE sono disponibili sia i valori OLD che i NEW, in
un trigger di INSERT sono disponibili solo i NEW mentre gli OLD sono tutti
NULL, viceversa in un trigger di DELETE sono disponibili solo gli OLD
mentre i NEW sono tutti NULL.
CLAUSOLA REFERENCING
Nellipotesi che nel database esista una tabella di nome OLD oppure
NEW possibile, per evitare fraintendimenti, utilizzare la clausola
REFERENCING per sostituire i prefissi OLD e NEW con prefissi a piacere
scelti dal programmatore.
WTO >create or replace trigger TEST_UPD_CLI
2 AFTER UPDATE ON CLIENTI
3 REFERENCING OLD as VECCHIO NEW as NUOVO
4 FOR EACH ROW
5 begin
6 dbms_output.put_line('Cliente '||:vecchio.cod_cliente||
7 ' vecchio nome '||:vecchio.nome||' nuovo '||:nuovo.nome);
8 end;
9 /
Trigger creato.
Aggiornate 8 righe.
WTO >rollback;
Rollback completato.
368
WTO >update clienti set nome='pippo';
Cliente 1 vecchio nome MARCO nuovo pippo
Cliente 2 vecchio nome GIOVANNI nuovo pippo
Cliente 3 vecchio nome MATTEO nuovo pippo
Cliente 4 vecchio nome LUCA nuovo pippo
Cliente 5 vecchio nome AMBROGIO nuovo pippo
Cliente 6 vecchio nome GENNARO nuovo pippo
Cliente 7 vecchio nome PASQUALE nuovo pippo
Cliente 8 vecchio nome VINCENZO nuovo pippo
Aggiornate 8 righe.
WTO >rollback;
Rollback completato.
Trigger creato.
Aggiornate 8 righe.
Creata 1 riga.
WTO >rollback;
Rollback completato.
369
Nel caso di trigger che scatta in risposta a pi eventi utile sapere nel
codice del trigger qual levento corrente. Oracle mette per questo motivo a
disposizione i predicati INSERTING, UPDATING e DELETING che
restituiscono TRUE o FALSE per indicare quale evento ha fatto scattare il
trigger. Lesempio precedente si pu modificare come segue:
WTO >create or replace trigger TEST_UPD_CLI
2 AFTER INSERT OR UPDATE OF NOME ON CLIENTI
3 FOR EACH ROW
4 begin
5 IF INSERTING THEN
6 dbms_output.put_line('Inserimento nuovo cliente');
7 ELSIF UPDATING THEN
8 dbms_output.put_line('Agg. cliente '||:old.cod_cliente);
9 END IF;
10 end;
11 /
Trigger creato.
Aggiornate 8 righe.
Creata 1 riga.
WTO >rollback;
Rollback completato.
DISABILITAZIONE ED ABILITAZIONE
Un trigger non pu essere eseguito esplicitamente, va in esecuzione
solo quando si verifica levento a cui collegato. per possibile disabilitare
un trigger per evitare che scatti. La disabilitazione di un trigger si esegue con
il comando
WTO >alter trigger TEST_UPD_CLI disable;
Trigger modificato.
Aggiornate 8 righe.
WTO >rollback;
370
Rollback completato.
Trigger modificato.
Aggiornate 8 righe.
WTO >rollback;
Rollback completato.
DIMENSIONE DI UN TRIGGER
La massima dimensione del codice di un trigger 32Kb, vivamente
consigliato, per, non superare le sessanta linee di codice. Se il codice
supera le sessanta linee di codice consigliabile mettere una parte del
codice in una stored procedure oppure in una funzione di database.
ORDINE DI ESECUZIONE
Su una tabella possono essere definiti pi trigger. In questo caso
lordine di esecuzione il seguente:
Before statement
Before each row
After each row
After statement
Nellesempio seguente si definiscono quattro trigger di UPDATE sulla
tabella COMUNI e si fanno scattare tutti con ununica istruzione per verificare
lordine di esecuzione.
WTO >create trigger com_b_u_s
2 before update on comuni
3 begin
4 dbms_output.put_line('Before update statement');
5 end;
6 /
Trigger creato.
371
4 begin
5 dbms_output.put_line('Before update row');
6 end;
7 /
Trigger creato.
Trigger creato.
Trigger creato.
Aggiornate 9 righe.
WTO >rollback;
Rollback completato.
UTILIZZI FREQUENTI
Gli utilizzi pi frequenti dei database trigger sono:
Valorizzazione automatica di campi
Controlli di validit complessi
Log delle operazioni DML
372
Vediamo nel seguito un esempio per ciascuna di queste casistiche.
Cominciamo dalla valorizzazione automatica di colonne. In caso di
inserimento in tabella CLIENTI vogliamo che il programmatore non debba
preoccuparsi di calcolare il corretto codice cliente da utilizzare.
Il trigger seguente valorizza automaticamente il codice cliente
utilizzando la sequenza SEQ_CLIENTE.
WTO >create or replace trigger clienti_bir
2 before insert on clienti
3 for each row
4 begin
5 select seq_clienti.nextval
6 into :new.cod_cliente
7 from dual;
8 end;
9 /
Trigger creato.
Selezionate 9 righe.
WTO >rollback;
Rollback completato.
373
15 select seq_clienti.nextval
16 into :new.cod_cliente
17 from dual;
18 end if;
19 end;
20 /
Trigger creato.
Creata 1 riga.
WTO >rollback;
Rollback completato.
Tabella creata.
Trigger creato.
Creata 1 riga.
Aggiornata 1 riga.
Aggiornata 1 riga.
CURRVAL
----------
26
Eliminata 1 riga.
WTO >rollback;
Rollback completato.
MUTATING TABLE
Un trigger FOR EACH ROW scatta durante lesecuzione di un
comando DML. Durante il trigger, dunque, la tabella in fase di
cambiamento (mutating in inglese) e non pu essere letta o modificata.
Facciamo un esempio. Aggiungiamo al trigger dellesempio precedente una
banale query che conta il numero di record presenti in CLIENTI.
WTO >create or replace trigger clienti_a_iud
2 after insert or update or delete on clienti
3 for each row
4 declare
5 evento varchar2(20);
6 n number;
375
7 begin
8 if inserting then
9 evento := 'Inserimento';
10 elsif updating then
11 evento := 'Aggiornamento';
12 else
13 evento := 'Cancellazione';
14 end if;
15
16 insert into log_clienti values
17 (sysdate, nvl(:old.cod_cliente,:new.cod_cliente),evento);
18
19 select count(*) into n
20 from clienti;
21 end;
22 /
Trigger creato.
Trigger creato.
Aggiornate 8 righe.
WTO >rollback;
Rollback completato.
376
Infatti, il trigger di tipo STATEMENT pu essere eseguito prima (se
BEFORE) o dopo (se AFTER) le modifiche del comando DML quando la
tabella ha uno stato comunque consistente.
Trigger INSTEAD OF
Abbiamo visto nel capitolo dellSQL che alcune viste sono modificabili,
su di esse possibile eseguire i comandi DML. La maggior parte delle viste,
per, non consente di eseguire comandi DML. Sulle viste non modificabili
possibile definire uno speciale tipo di trigger, il trigger INSTEAD OF.
Questo tipo di trigger scatta al posto delloperazione DML per cui
definito. Nellesempio seguente si definisce la vista CLI_COM.
WTO >select * from cli_com;
Selezionate 8 righe.
Aggiornata 1 riga.
WTO >rollback;
Rollback completato.
377
Trigger creato.
Creata 1 riga.
Procedure created.
379
5 end;
6 /
Function created.
Procedure created.
9 rows selected.
REF_NAME REFERENCED_TYPE
---------------------------------------- ---------------
STANDARD PACKAGE
SYS_STUB_FOR_PURITY_ANALYSIS PACKAGE
F1 FUNCTION
STANDARD PACKAGE
SYS_STUB_FOR_PURITY_ANALYSIS PACKAGE
P2 PROCEDURE
STANDARD PACKAGE
SYS_STUB_FOR_PURITY_ANALYSIS PACKAGE
CLIENTI TABLE
380
9 rows selected.
REF_NAME REFERENCED_TYPE
---------------------------------------- ---------------
1)STANDARD PACKAGE
1)SYS_STUB_FOR_PURITY_ANALYSIS PACKAGE
1)F1 FUNCTION
2)STANDARD PACKAGE
2)SYS_STUB_FOR_PURITY_ANALYSIS PACKAGE
2)P2 PROCEDURE
3)STANDARD PACKAGE
3)SYS_STUB_FOR_PURITY_ANALYSIS PACKAGE
3)CLIENTI TABLE
9 rows selected.
REFERENCED_NAME REFERENCED_TYPE
---------------------------- ---------------
F1 FUNCTION
P2 PROCEDURE
SYS_STUB_FOR_PURITY_ANALYSIS PACKAGE
STANDARD PACKAGE
CLIENTI TABLE
381
O12c>create or replace function test_wl return number
2 ACCESSIBLE BY (test_call_1, test_call_2) is
3 begin
4 return 1;
5 end;
6 /
Funzione creata.
Procedura creata.
O12c>sho err
Errori in FUNCTION TEST_CALL_3:
LINE/COL ERROR
-------- -------------------------------------------------------
3/3 PL/SQL: Statement ignored
3/10 PLS-00904: privilegio non sufficiente per avere accesso
a oggetto TEST_WL
Table created.
1 row created.
382
WTO >commit;
Commit complete.
Function created.
LEGGI
---------
1
Grant succeeded.
LEGGI
---------
1
Table created.
383
WTO >insert into test values (2);
1 row created.
WTO >commit;
Commit complete.
LEGGI
---------
1
Function created.
LEGGI
---------
1
LEGGI
---------
2
Concessione riuscita.
Concessione riuscita.
Tabella creata.
Creata 1 riga.
FUN_BEQ
----------
1
385
FUN_BEQ
----------
1
Concessione riuscita.
Concessione riuscita.
Tabella creata.
Creata 1 riga.
FUN_BEQ
----------
2
FUN_BEQ
----------
1
Vista eliminata.
Vista creata.
Concessione riuscita.
Colleghiamoci ad USR2:
usr1>conn usr2/usr2@corsopdb
Connesso.
FUN_BEQ
----------
2
FUN_BEQ
----------
2
387
Ad esempio guardiamo il codice PL/SQL della funzione LEGGI definita
nel paragrafo precedente.
WTO >select * from user_source
2* where name='LEGGI'
7 rows selected.
TEXT
-------------------------------
function leggi return number
authid current_user is
a number;
begin
select a into a from test;
return a;
end;
7 rows selected.
TRIGGER_BODY
-------------------------------------------
declare
388
n number;
begin
select count(*) into n
from clienti;
end;
Function created.
LEGGI
---------
1
389
WTO >select text
2 from user_source
3 where name='LEGGI'
4 order by line;
TEXT
-----------------------------------------------------------------
function leggi wrapped
a000000
b2
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
8
72 a2
pxahtprUcMdJlRqLRR04tdlJsjMwg2JHf8tGfHSiszsQGL6A5S85S6BX8Quxw+eozXMeYw6S
lbf58TzmmO6/h7GyFxr9Vv700SoL64hiVd5SXQ6EB3exbVlxPTYE5MJExXdRJJM0u+dKFii8
cqNG35xyLMvHpAM=
390
2 (str in varchar2) return date is
3 retDate date;
4 begin
5 retDate := to_date(str,'yyyy-mm-dd');
6 return retDate;
7 end;
8 /
Funzione creata.
STRINGA2D
---------
31-GEN-10
Funzione creata.
STRINGA2D
---------
391
stata definita una nuova eccezione DATA_NON_CORRETTA, ma
nessuno l'avrebbe mai sollevata se non l'avessimo associata mediante
PRAGMA all'errore ORA-1841.
A questo punto Oracle sa che in caso si verifichi l'errore ORA-1841
deve passare il controllo al blocco exception dove abbiamo provveduto a
gestire la situazione.
La PRAGMA RESTRICT_REFERENCES consente di dichiarare
esplicitamente il livello di purezza di un programma PL/SQL, cio se esso
legge/scrive oggetti di database o variabili di package.
In alcuni contesti, infatti, solo funzioni che garantiscono tali restrizioni
possono essere utilizzate.
Un esempio classico il seguente.
Definiamo un package composto da un'unica funzione che aggiorna
una tabella di DB e torna un numero:
WTO> create or replace package pack is
2 function a return number;
3 end;
4 /
Package creato.
A
----------
2
WTO> select pack.a from dual;
select pack.a from dual
*
ERRORE alla riga 1:
ORA-14551: impossibile eseguire un'operazione DML all'interno di una
query
ORA-06512: a "WTO_ESEMPIO.PACK", line 4
392
Come facciamo a controllare meglio la cosa fin dalla compilazione?
Utilizzando, appunto, PRAGMA RESTRICT_REFERENCES.
Se sappiamo che la funzione A dovr essere utilizzata in SQL, infatti,
possiamo definirla come segue:
WTO> create or replace package pack is
2 function a return number;
3 pragma restrict_references(a,'WNDS');
4 end;
5 /
Package creato.
LINE/COL ERROR
-------- ------------------------------------------------------
2/1 PLS-00452: Il sottoprogramma 'A' viola il pragma associato
Package creato.
393
Se valorizziamo la variabile var in qualunque modo, questa rester
valorizzata per tutta la sessione:
WTO> begin
2 pack.var := 1;
3 end;
4 /
Package creato.
WTO> begin
2 pack.var := 1;
3 dbms_output.put_line('Var='||pack.var);
4 end;
5 /
Var=1
SUM(SAL)
----------
29025
Funzione creata.
Funzione creata.
Aggiornate 14 righe.
395
begin
totale := calcola_nominali + calcola_interessi;
end;
return s;
end;
return s;
end;
select sum(interessi)
into v_calcola_interessi
from operazioni;
397
9 Cloud e Multitenant Architecture
400
9.3.3 Container corrente
In una sessione il container corrente quello in cui la sessione in
esecuzione. Il container corrente pu essere Root oppure un PDB.
La sessione pu cambiare container corrente mediante listruzione
ALTER SESSION SET CONTAINER come nellesempio che segue. La
sessione connessa allutente SYSTEM. Per visualizzare il container
corrente si utilizza la variabile dambiente CON_NAME:
CON_NAME
------------------------------
CDB$ROOT
NAME PDB
------------------------------ ----------------------------
corsopdb CORSOPDB
corsocdbXDB CDB$ROOT
corsocdb CDB$ROOT
SYS$BACKGROUND CDB$ROOT
SYS$USERS CDB$ROOT
Si tratta dei servizi di default del container Root e del servizio collegato
al PDB che abbiamo creato in fase dinstallazione.
Per modificare il container corrente si pu utilizzare il comando ALTER
SESSION SET CONTAINER:
SQL> alter session set container=CORSOPDB;
Modificata sessione.
CON_NAME
------------------------------
CORSOPDB
NAME PDB
------------------------------ ----------------------------
corsopdb CORSOPDB
401
Per evitare un inutile spreco di spazio, i dati di dizionario comuni a tutti
i PDB vengono conservati solo in Root. In questo caso ogni PDB ha nel suo
dizionario un semplice link ad un record presente nel dizionario di Root. In
pi, ovviamente, ogni PDB ha nel proprio dizionario i dati reali relativi ai
propri oggetti.
Ovviamente ci sono viste di dizionario che consentono di leggere
trasversalmente le informazioni relative a pi container/PDB. Tra queste
troviamo le V$ e GV$, gi presenti nelle precedenti versioni di Oracle, e le
nuove viste il cui nome comincia per CDB_.
In queste viste la Colonna CON_ID consente di individuare il container
in cui lo specifico oggetto si trova.
Quando il container corrente un PDB, le viste CDB_ possono essere
lette ma forniscono informazioni solo relative al PDB sesso. Se il container
corrente Root, invece, le viste CDB_ forniscono informazioni relative al
container Root ed a tutti i PDB per cui lutente che esegue la query ha
privilegi daccesso.
CON_NAME
------------------------------
CDB$ROOT
Utente creato.
402
Gli utenti comuni non devono necessariamente avere gli stessi privilegi
su tutti i container, possono connettersi a tutti i container (incluso Root) per
cui hanno il privilegio CREATE SESSION.
Come detto, hanno le medesime identit e caratteristiche in tutti i
container ma in ogni container possono avere uno schema differente.
Un utente locale esiste solo allinterno di uno specifico PDB.
SQL> alter session set container=CORSOPDB;
Modificata sessione.
Utente creato.
Concessione riuscita.
Modificata sessione.
Concessione riuscita.
403
Per default listruzione GRANT utilizza la clausola
CONTAINER=CURRENT, quindi i privilegi vengono assegnati localmente in
un unico container.
E per fermarlo:
O12c> alter pluggable database corsopdb close;
404
9.6.2 Connettersi al database
Per connettersi al CDB si procede come in un normale non-CDB. Per
collegarsi PDB, invece, necessario utilizzare il nome del servizio ad esso
associato. Il tnsnames.ora, quindi, dovr essere configurato in questo modo:
CORSOPDB =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
)
(CONNECT_DATA =
(UR=A)
(SERVICE_NAME = corsopdb)
)
)
405
A questo punto, nel tnsnames rimuoviamo il parametro UR=A e
proviamo a connetterci a corsopdb:
O12c> conn corso/corso@corsopdb
ERROR:
ORA-12526: TNS: listener: tutte le istanze appropriate sono in modalit
limitata
406
Nel CDB da cui labbiamo scollegato non lo possiamo pi utilizzare. Il
PDB, infatti, in stato UNPLUGGED:
PDB_NAME STATUS
-------------------- -------------
CORSOPDB UNPLUGGED
PDB$SEED NORMAL
PDB_NAME STATUS
-------------------- -------------
PDB$SEED NORMAL
CORSOPDB NEW
PDB_NAME STATUS
-------------------- -------------
PDB$SEED NORMAL
CORSOPDB NORMAL
407
Lerrore indica che bisogna specificare come gestire i nomi dei datafile.
I datafile presenti in questo momento sono quelli relativi al CDB e quelli
relativi a CORSOPDB:
O12c>select name from v$datafile;
NAME
---------------------------------------------------------------
D:\ORACLE\ORADATA\CORSOCDB\SYSTEM01.DBF
D:\ORACLE\ORADATA\CORSOCDB\PDBSEED\SYSTEM01.DBF
D:\ORACLE\ORADATA\CORSOCDB\SYSAUX01.DBF
D:\ORACLE\ORADATA\CORSOCDB\PDBSEED\SYSAUX01.DBF
D:\ORACLE\ORADATA\CORSOCDB\UNDOTBS01.DBF
D:\ORACLE\ORADATA\CORSOCDB\USERS01.DBF
D:\ORACLE\ORADATA\CORSOCDB\CORSOPDB\SYSTEM01.DBF
D:\ORACLE\ORADATA\CORSOCDB\CORSOPDB\SYSAUX01.DBF
D:\ORACLE\ORADATA\CORSOCDB\CORSOPDB\SAMPLE_SCHEMA_USERS01.DBF
D:\ORACLE\ORADATA\CORSOCDB\CORSOPDB\CORSO01.DBF
D:\ORACLE\ORADATA\CORSOCDB\CORSOPDB\TEST.DBF
PDB_NAME STATUS
-------------------- -------------
CORSOPDB_COPIA NEW
PDB$SEED NORMAL
CORSOPDB NORMAL
PDB_NAME STATUS
-------------------- -------------
CORSOPDB_COPIA NORMAL
PDB$SEED NORMAL
CORSOPDB NORMAL
NAME
--------------------------------------------------------------
D:\ORACLE\ORADATA\CORSOCDB\SYSTEM01.DBF
D:\ORACLE\ORADATA\CORSOCDB\PDBSEED\SYSTEM01.DBF
D:\ORACLE\ORADATA\CORSOCDB\SYSAUX01.DBF
D:\ORACLE\ORADATA\CORSOCDB\PDBSEED\SYSAUX01.DBF
D:\ORACLE\ORADATA\CORSOCDB\UNDOTBS01.DBF
D:\ORACLE\ORADATA\CORSOCDB\USERS01.DBF
D:\ORACLE\ORADATA\CORSOCDB\CORSOPDB\SYSTEM01.DBF
D:\ORACLE\ORADATA\CORSOCDB\CORSOPDB\SYSAUX01.DBF
D:\ORACLE\ORADATA\CORSOCDB\CORSOPDB\SAMPLE_SCHEMA_USERS01.DBF
D:\ORACLE\ORADATA\CORSOCDB\CORSOPDB\CORSO01.DBF
D:\ORACLE\ORADATA\CORSOCDB\CORSOPDB\TEST.DBF
D:\ORACLE\ORADATA\CORSOCDB\CORSOPDB_COPIA\SYSTEM01.DBF
D:\ORACLE\ORADATA\CORSOCDB\CORSOPDB_COPIA\SYSAUX01.DBF
D:\ORACLE\ORADATA\CORSOCDB\CORSOPDB_COPIA\SAMPLE_SCHEMA_USERS01.DBF
D:\ORACLE\ORADATA\CORSOCDB\CORSOPDB_COPIA\CORSO01.DBF
D:\ORACLE\ORADATA\CORSOCDB\CORSOPDB_COPIA\TEST.DBF
16 righe selezionate.
409
O12c>show con_name
CON_NAME
------------------------------
CDB$ROOT
PDB_NAME STATUS
------------------------------ -------------
CORSOPDB_COPIA NORMAL
PDB$SEED NORMAL
CORSOPDB NORMAL
O12c>conn system/corso@CORSOPDB_COPIA
Connesso.
PDB_NAME STATUS
410
------------------------------ -------------
CORSOPDB_COPIA NORMAL
PDB$SEED NORMAL
CORSOPDB NORMAL
Trigger creato.
PDB_NAME STATUS
------------------------------ -------------
CORSOPDB_COPIA NORMAL
PDB$SEED NORMAL
CORSOPDB NORMAL
411
CORSOPDB_COPIA2 UNUSABLE
E sul filesystem sono stati creati i relativi data file e temp file:
412
10 Prerequisiti
Tabella FATTURE
414
fattura presente il dato Codice Cliente mediante il quale possibile
ricavare, in maniera univoca poich il Codice Cliente chiave primaria nella
tabella CLIENTI, le informazioni del cliente a cui stata emessa la fattura. La
colonna Codice Cliente presente nella tabella FATTURE detta chiave
esterna (foreign key). La chiave esterna cos definita fa riferimento alla
chiave primaria definita sulla tabella CLIENTI. Una chiave esterna e la chiave
primaria a cui essa fa riferimento sono di fatto lo stesso dato, nel nostro
esempio il codice del cliente.
I migliori database relazionali garantiscono automaticamente lintegrit
referenziale, cio
non possibile assegnare un valore specifico ad una chiave esterna se
quello stesso valore non stato gi definito tra i valori della chiave
primaria a cui essa fa riferimento. Non possiamo assegnare il valore
555555 al codice cliente di una fattura perch non esiste un cliente in
CLIENTI che ha quel codice.
Non possibile cancellare una riga da una tabella se ci sono chiavi
esterne in altre tabelle che fanno riferimento a quello specifico valore.
Nel nostro esempio non sarebbe possibile cancellare i clienti 111111 e
222222 perch essi hanno fatture collegate, ma sarebbe possibile
cancellare il cliente 333333 perch non ha fatture collegate.
10.1.3 DBA
Il DBA (database administrator) un professionista dellinformatica
che si occupa di installare, aggiornare e gestire uno o pi database. Tutte le
grandi organizzazioni hanno alle proprie dipendenze, direttamente o
mediante contratti di consulenza stipulati con altre aziende, un gruppo di
DBA che gestisce i database aziendali. Si tratta di una figura professionale
molto critica visto che il vero patrimonio di tante grandi aziende sta
soprattutto nei dati che esse gestiscono.
415
diventato, negli anni, uno standard de facto per la realizzazione del modello
concettuale dei dati di un database. Il modello si basa sullindividuazione
delle entit del sistema e delle relazioni che collegano le diverse entit. Per
ogni entit vanno poi specificati gli attributi, cio i singoli dati da gestire, e gli
identificatori, cio le potenziali chiavi primarie ed univoche. Anche le relazioni
in taluni casi possono avere degli attributi.
10.2.2 Normalizzazione
Completato il modello concettuale bisogna trasformarlo in uno schema
tabellare relazionale. Una prima trasformazione grossolana pu essere
effettuata applicando alcune regole fisse allo schema concettuale, ad
esempio:
Da ogni entit si ottiene una tabella,
da ogni relazione avente attributi si ottiene una tabella,
le altre relazioni diventano chiavi esterne.
Si individua, in questo modo, un insieme di tabelle relazionali. Tali
tabelle per potrebbero presentare forti limitazioni oppure delle ridondanze di
dati. Per eliminare le ridondanze si applica il processo di normalizzazione.
Tale processo consiste nella trasformazione graduale delle tabelle in modo
che queste rispettino le regole imposte dalle forme normali. Tra le molte che
sono state enunciate dagli esperti di analisi dei dati, nel seguito saranno
descritte le forme normali che si considerano indispensabili per ottenere un
database a bassa ridondanza: la prima, la seconda e la terza forma normale.
Per ragionare su un esempio concreto si consideri la seguente tabella:
Tabella CLIENTI Versione 1
Codice Cognome Indirizzo Comune Prov. Telefono
111111 Rossi Via Rossi, 2 Pomezia RM Casa 0666778899
Cell 3351234567
222222 Verdi Via Verdi, 1 Rho MI Casa 0233445566
Cell 3387654321
333333 Bianchi Via Bianchi, 3 Casoria NA Casa 0819988774
Cell 3491234567
444444 Gialli Via Gialli, 1 Rho MI Cell 3177654321
416
Tabella CLIENTI Versione 2
Codice Cognome Indirizzo Comune Prov. Tel. Casa Tel. Cell
111111 Rossi Via Rossi, 2 Pomezia RM 0666778899 3351234567
222222 Verdi Via Verdi, 1 Rho MI 0233445566 3387654321
333333 Bianchi Via Bianchi, 3 Casoria NA 0819988774 3491234567
444444 Gialli Via Gialli, 1 Rho MI 3177654321
417
dipendenza parziale, della descrizione dal codice articolo e della data dal
numero ordine, di conseguenza saranno individuate due nuove tabelle:
Tabella DETTAGLIO ORDINI
Num. Cod. Quantit
Ordine Prodotto
111111 XY123 200
111111 AZ321 100
222222 AS333 130
333333 AZ321 230
444444 XY123 150
Tabella ORDINI
Num. data
Ordine
111111 1/9/2010
222222 3/9/2010
333333 5/9/2010
444444 7/9/2010
Tabella PRODOTTI
Cod. Descr. prodotto
Prodotto
XY123 Bulloni mis. 8
AZ321 Viti da 5mm
AS333 Viti da 7mm
Tabella COMUNI
Codice Nome Prov.
Comune Comune
G811 Pomezia RM
H264 Rho MI
B990 Casoria NA
419
10.3.1 Architettura Hardware
Con grande approssimazione si pu affermare che un computer sia
formato dalle seguenti componenti elettroniche (Hardware).
Un processore (CPU, Central Processing Unit) che in grado di
compiere ad altissima velocit poche operazioni elementari come
accedere alla memoria per leggere o scrivere un dato. I computer
moderni sono spesso dotati di pi CPU in modo da poter compiere pi
operazioni contemporaneamente.
Una memoria volatile (RAM, Random Access Memory), limitata nella
dimensione ma che garantisca una velocit di accesso molto alta.
Volatile significa che i dati in essa immagazzinati andranno persi allo
spegnimento del computer.
Una memoria fissa (Hard Disk Drive, disco rigido) molto pi ampia ma
meno veloce della RAM in cui i dati possano restare immagazzinati per
un tempo indeterminato. La memoria fissa pu essere interna o
esterna rispetto al calcolatore e solitamente utilizza una tecnologia
basata su dischi magnetici.
Una serie di periferiche di input/output che consentano allessere
umano o ad altri computer di interagire con il calcolatore: tastiera,
monitor, mouse, porte di comunicazione, schede di rete, stampanti,
ecc.
Una rete interna di interconnessioni (BUS) che consentano al
processore di controllare tutte le periferiche ed utilizzare le memorie.
420
gli strumenti di Office Automation come Microsoft Office ed
OpenOffice, che consentono di scrivere documenti, fogli di calcolo e
presentazioni;
i browser internet come Internet Explorer, Mozilla Firefox e Google
Chrome che consentono di navigare in internet;
i database come Oracle, Microsoft SQL Server ed IBM DB2 che
consentono di archiviare dati;
gli IDE (Integrated Development Environment) come Eclipse o
NetBeans, che consentono di creare software utilizzando uno dei tanti
linguaggi di programmazione esistenti.
123 = 1 26 + 1 25 + 1 24 + 1 23 + 0 22 + 1 21 + 1 20
Sottintendendo le potenze, come facciamo solitamente nel sistema
decimale, si ottiene la rappresentazione binaria del numero 123:
1111011
Poich nel sistema binario sono disponibili solo due cifre i numeri
crescono molto rapidamente di lunghezza, ma solo un problema di
rappresentazione grafica: cinque dita sono sempre cinque, sia che le si
rappresenti con la cifra 5 che con la stringa di cifre 101!
Esattamente nello stesso modo si ragiona con il sistema esadecimale
dove le cifre sono ben sedici, da 0 a 9 pi le lettere A, B, C, D, E, F.
Ovviamente nel caso del sistema esadecimale i numeri avranno una
rappresentazione pi corta di quella decimale. La tabella seguente
rappresenta i numeri da uno a venti in sistema decimale, binario ed
esadecimale. Anche negli altri sistemi di numerazione, come in quello
decimale, gli zeri aggiunti alla sinistra del numero non ne cambiano il valore.
421
Sistema Decimale Sistema Binario Sistema Esadecimale
1 1 1
2 10 2
3 11 3
4 100 4
5 101 5
6 110 6
7 111 7
8 1000 8
9 1001 9
10 1010 A
11 1011 B
12 1100 C
13 1101 D
14 1110 E
15 1111 F
16 10000 10
17 10001 11
18 10010 12
19 10011 13
20 10100 14
422
10.4.3 La tabella ASCII
Nel paragrafo precedente si visto come vengono rappresentati i
numeri interi nella memoria di un computer. La maggior parte delle volte per
ci interessa memorizzare tutti i caratteri, non solo i numeri. Serve dunque un
modo per associare ogni carattere (lettere minuscole, maiuscole, cifre, segni
di punteggiatura, caratteri speciali eccetera) ad un numero intero che sia poi
rappresentabile con una stringa di bit.
Questa funzione svolta nei sistemi Windows ed Unix dalla tabella
ASCII (American Standard Code for Information Interchange). Si tratta di una
tabella che associa ogni numero da 0 a 255 (quindi un Byte) ad un carattere.
Se in un sistema basato su tabella ASCII si intende memorizzare la
lettera M di fatto sar memorizzata la stringa di bit 01001101.
Ovviamente 255 codici sono ampiamente sufficienti per individuare
tutti i caratteri utilizzati nelle lingue occidentali, ma sono pochi per i caratteri
di molte altre lingue del mondo. Per questo motivo la codifica ASCII stata
estesa con la codifica UNICODE che basata attualmente su 21 cifre binarie
e consente di rappresentare circa un milione di caratteri.
Non tutti i sistemi operativi sono basati sulla codifica ASCII/Unicode. I
mainframe IBM, ad esempio, utilizzano la codifica EBCDIC, anchessa
basata su otto bit ma associati differentemente ai caratteri da rappresentare.
La stringa di bit 01001101 che in ASCII rappresenta la lettera M, in
EBCDIC rappresenta la parentesi tonda aperta (.
423
10.5.2 Virgola mobile
Unaltra tecnica di memorizzazione dei numeri consiste nel non
assumere un fattore di scala fisso ma determinarlo per ogni numero che si
archivia. Un qualunque numero razionale x pu essere espresso nella
notazione esponenziale
x = mantissa base esponente (1)
Dove la mantissa un numero maggiore o uguale di 0,1 e minore di 1,
la base pu essere scelta liberamente (le tre basi pi utilizzate sono 2, 10 e
16) e lesponente un numero intero relativo.
Accettando limprecisione dovuta ad un inevitabile arrotondamento,
anche tutti i numeri reali possono essere espressi in notazione esponenziale
per di pi utilizzando un limitato numero di cifre per rappresentare la
mantissa. La rappresentazione a virgola mobile consiste dunque nel fissare
la base ed archiviare per ogni numero sia la mantissa che lesponente.
Quando il numero dovr essere ricostruito a partire da mantissa ed
esponente sar utilizzata la formula (1).
424
Per trovare lelemento cercato la ricerca dicotomica richiede al pi un
numero di iterazioni pari a Log 2 ( N ) arrotondato per eccesso ed in media
un numero di accessi pari a Log 2 ( N ) 1 .
425
10.8.2 Intersezione di insiemi
Se S e T sono due insiemi, si chiama intersezione di S e T il nuovo
insieme costituito dagli elementi di S che sono inclusi anche in T.
Ovviamente possibile che S e T non abbiano elementi in comune, in tal
caso lintersezione di S e T linsieme vuoto ed S e T si dicono disgiunti.
anche possibile che S e T contengano esattamente gli stessi elementi, in tal
caso la loro intersezione coincide con entrambi gli insiemi di partenza. Il
numero di elementi contenuti nellintersezione sicuramente minore o
uguale del numero di elementi contenuti nei singoli insiemi.
426
Le proposizioni possono combinarsi tra loro mediante alcuni operatori
per formare nuove proposizioni:
427
10.9.5 Leggi di De Morgan
Gli operatori presentati nei paragrafi precedenti sono legati da due
importanti regole che prendono il nome di leggi di De Morgan. Siano p e q
due proposizioni
NOT (p AND q) = (NOT p) OR (NOT q)
NOT (p OR q) = (NOT p) AND (NOT q)
Il senso molto pi semplice di quello che pu sembrare dai simboli,
la negazione di oggi piove e domani sabato oggi non piove oppure
domani non sabato, viceversa la negazione di oggi piove oppure domani
sabato oggi non piove e domani non sabato.
429
Indice Analitico
ASIN 222
Assegnazione 300
% ATAN 222
ATAN2 222
AUTHID CURRENT_USER 384
%ISOPEN 314
AVG 167
%NOTFOUND 313
Avviare Oracle 20
%ROWCOUNT 314
%ROWTYPE 328
%TYPE 299
B
A balanced tree 52
BEGIN 296
BETWEEN 150
ABS 218
binary digit 422
Accassible By 381
bit 422
ACOS 222
Bitmap 53
ADD_MONTHS 224
BLOB 70
albero bilanciato 52
Blocchi anonimi 295
Algoritmi di hash 425
blocco 13
Algoritmi di ricerca 424
BOOLEAN 298
Alias di colonna 137
B-tree 51
ALL 276
Bulk collect 336
ALTER 90
BUS 420
AND 154
Byte 422
ANY 275
Applicazioni software 421
APPLY 265
Architettura di un computer 420 C
Architettura Hardware 420
Architettura Software 420 CASE 247; 302
Archiver 16 CDB 17; 399
ARCn 16 CDB$ROOT 400
Aritmetica sulle date 223 CEIL 220
Array Associativi 330 Central Processing Unit 420
Arrestare Oracle 20 CHAR 68
ASCII 218 check constraint 50
ASCII 423 Check option 56
430
checkpoint 12; 15 database administrator 415
chiave esterna 50; 415 Database buffer Cache 13
chiave primaria 50; 414 Database link 58
chiave univoca 50 database relazionale 414
CHR 218 normalizzazione 416
CKPT 12 prima forma normale 416
client 22 progettazione 415
CLOB 69 seconda forma normale 417
CLOSE 314 terza forma normale 418
Cloud Computing 398 Database Writer 12
Cloud Privato 398 datafile 13
Cloud Pubblico 398 DATE 70
Cluster di tabelle 54 Date ed orari 70
Cluster Index 55 Dati alfanumerici 68
COALESCE 239 Dati binari 70
Collection 336 DBA 415
Colonne di una tabella 49 DBMS 413
Colonne invisibili 94 DBWn 12
COLUMN_VALUE 141 DCL 292
Commenti 298 DDL 71
COMMIT 281 Deadlock 291
CONCAT 208 DECLARE 296
Concatenazione 206 DECODE 245
Condizioni 143 dedicated server 23
Congiunzione 427 Default Value 112; 113
CONNECT BY 179 DELETE 337
connect string 23 DELETE 125
CONNECT_BY_ISCYCLE 141 DESC 36
CONNECT_BY_ISLEAF 141 DESCRIBE 36
Constraint 49; 56 Dipendenze 378
Container 400 disco rigido 420
control file 15 Disgiunzione 427
Conversioni implicite 230 dispatcher 23
COS 222 DISTINCT 164
Costanti 300 Dizionario dati 45
COUNT 342 DML 108
COUNT 168 DML Trigger 365
CPU 420 DROP 101
Creare un utente 30 DUAL 139
CREATE 71 DUP_VAL_ON_INDEX 317
CROSS APPLY 265
CURRENT_DATE 227
CURRENT_TIMESTAMP 228 E
CURRVAL 84; 141
CURSOR FOR LOOP 315
E. F. Codd 413
Cursori 313
EBCDIC 423
Eccezioni mute 324
Eccezioni predefinite 317
D Eccezioni utente 323
END 296
data block 13 Enterprise Manager 19
Data Dictionary 402 entit 414
database 11; 413 Espressioni regolari 241
431
Estensioni Object-Oriented 59 di conversione 230
EXCEPTION 296; 316 EXP 221
EXECUTE IMMEDIATE 309 EXTRACT 228
EXISTS 340 FLOOR 220
EXISTS 276 GREATEST 250
EXP 221 INITCAP 213
EXTEND 339 INSTR 211
extent 14 LAST_DAY 225
External Table 49 LEAST 251
EXTRACT 228 LENGTH 212
LN 221
LNNVL 240
F LOG 221
LOWER 213
LPAD 215
FETCH 313
LTRIM 214
FETCH 187
MOD 222
file di controllo 15
MONTHS_BETWEEN 224
Firma 345; 352
NEXT_DAY 225
FIRST 341
NULLIF 241
FLASHBACK TABLE 107
NVL 237
FLOOR 220
NVL2 238
FOR 305
POWER 221
foreign key 50; 415
REGEXP_COUNT 244
Formati
REGEXP_INSTR 242
date 232
REGEXP_LIKE 244
numeri 236
REGEXP_REPLACE 242
Funzioni 352
REGEXP_SUBSTR 243
Funzioni di gruppo 165
REMAINDER 222
AVG 167
REPLACE 216
COUNT 168
ROUND 219; 226
MAX 167
RPAD 216
MIN 166
RTRIM 214
STDDEV 168
SIGN 222
SUM 165
SIN 222
VARIANCE 167
SINH 222
Funzioni di hash 425
SQRT 221
Funzioni PL/SQL 58
SUBSTR 209
Funzioni predefinite 206
sui numeri 218
ABS 218
sulle date 223
ACOS 222
SYSDATE 223
ADD_MONTHS 224
SYSTIMESTAMP 223
ASCII 218
TO_CHAR 230
ASIN 222
TO_DATE 231
ATAN 222
TO_NUMBER 231
ATAN2 222
TO_TIMESTAMP 232
CEIL 220
TRANSLATE 217
CHR 218
TRIM 215
COALESCE 239
TRUNC 219; 227
CONCAT 208
UPPER 213
COS 222
CURRENT_DATE 227
CURRENT_TIMESTAMP 228
DECODE 245
432
G K
GigaByte 422 KiloByte 422
GOTO 306
GRANT 292
GREATEST 250 L
GROUP BY 165
Large Pool 13
LAST 341
H LAST_DAY 225
LATERAL 266
Hard Disk Drive 420 LEAST 251
Hash 425 Leggi di De Morgan 428
Hash Cluster 55 LENGTH 212
HAVING 170 LEVEL 141
LGWR 12
LIKE 152
I LIMIT 342
Linux 420
listener 22
IDE 421
Literals 108
Identity 117
LN 221
IF THEN ELSE 300
LNNVL 240
IN 150
Lock 290
IN (subquery) 276
LOG 221
Indexed Cluster 55
LOG ERRORS 131
Index-Organized Tables 54
log switching 15; 16
Indice Bitmap 53
Log Writer 12
Indice B-tree 51
Logica delle proposizioni 426
Indici 51; 53
LONG 69
INITCAP 213
LONG RAW 71
INNER JOIN 254
LOOP 303
INSERT 109
LOWER 213
Installazione del database 17
LPAD 215
Installazione multitenant 17
LTRIM 214
INSTR 211
Integrated Development Environment
421
integrit referenziale 50; 415 M
INTERSECT 272
INVALID_NUMBER 318 Materialized views 56
IOT 54 MAX 167
IS NOT NULL 144 MegaByte 422
IS NULL 144 MERGE 126
istanza 11; 12 Metodi delle collezioni 337
MIN 166
MINUS 272
J MOD 222
MODEL 196
MONTHS_BETWEEN 224
Java Pool 13
MOUNT 20
JOIN 251
multiplexed 15; 16
Multitenant Architecture 399
433
N P
Negazione 427 Package 357
Nested Tables 335 Packege PL/SQL 58
NEXT 343 Paginazione dei dati 187
NEXT_DAY 225 Partizioni 49
NEXTVAL 84; 141 Pattern Matching 191
NO_DATA_FOUND 319 PDB 17; 399
NOMOUNT 20 Create 407
non-CDB 17; 399 Duplicazione 407
Normalizzazione 416 Shutdown 404
NOT 156 Startup 404
NOT BETWEEN 150 Tnsnames 405
NOT IN 150 Trigger 409
NOT LIKE 152 Unplug 406
Null 112; 113 Personalizzare SQL*Plus 32
NULL 307 PGA 13
NULLIF 241 PIVOT 175
NUMBER 69 PL/SQL Tables 330
Numeri ed importi 69 PMON 12
NVL 237 POWER 221
NVL 237 PRAGMA
NVL2 238 autonomous_transaction 394
exception_init 390
inline 395
O restrict_references 392
serially_reusable 393
Predicati 428
OFFSET 187
Prima forma normale 416
Oggetti del DB 45
primary key 50; 414
Oggetti PL/SQL 58
PRIOR 343
OPEN 313
Private Cloud 398
OPEN 20
Privilegi 292
Operatori
Procedure 344
aritmetici 207
Procedure PL/SQL 58
di concatenazione 206
Process Monitor 12
di confronto 143
processi di base 11
logici 154
Prodotto cartesiano
Operatori Insiemistici 268
di insiemi 426
Operatori Logici 426
di tabelle 252
congiunzione 427
Progettazione di un db 415
disgiunzione 427
Program Global Area 13
negazione 427
Proiezioni 137
Regole di precedenza 427
proposizione 426
OR 155
Pseudocolonne 141
oradim 19
Public Cloud 398
ORDER BY 159
PURGE 106
Ordinamento 159
OTHERS 320
OUTER APPLY 266
Outer join 261 Q
OUTER JOIN 256
Query 136
Query gerarchiche 179
434
Selezioni 143
R Sequence 116; 118
di sessione 87
Raggruppamenti 164 Sequenze 57
RAISE 322; 327 server 22
RAISE_APPLICATION_ERROR 322 servizio client 22
RAM 420 SET 36
Random Access Memory 420 SET TRANSACTION 286
Rappresentazioni numeriche 423 SGA 12
RAW 70 Shared Pool 13
RDBMS 414 shared server 23
Real Application Clusters 11 SHOW 35
RECORD 327 Shutdown 20
recovery 15 Abort 20
Redo Log Buffer 13 Immediate 20
Redo Log file 15 Normal 20
REGEXP_COUNT 244 Transactional 20
REGEXP_INSTR 242 SIGN 222
REGEXP_LIKE 244 SIN 222
REGEXP_REPLACE 242 SINH 222
REGEXP_SUBSTR 243 Sinonimi 57
relazione 415 Sistema binario 421
REMAINDER 222 Sistema esadecimale 421
RENAME 101 Sistema operativo 420
REPLACE 216 SMON 12
RETURN 352 SQL 66
REVOKE 293 SQL Developer 42
Ricerca Binaria 424 SQL Dinamico 309
Ricerca Dicotomica 424 SQL Statico 308
Ricerca sequenziale 424 SQL Types 298
Ricerche innestate 273 SQL*Plus 19; 31
Ricerche su pi tabelle 251 SQLCODE 321
ROLLBACK 283 SQLERRM 321
ROLLUP 170 SQRT 221
Root Container 400 Startup 20
ROUND 219; 226 STDDEV 168
ROWID 51; 141 Stored Function 58
ROWNUM 142; 173 Stored Procedure 58
RPAD 216 stringa di connessione 23
RTRIM 214 Subprogram Inlining 395
Ruoli Subquery 273
Comuni 403 correlate 279
Locali 403 Operatori di confronto 274
RUOLI 294 scorrelate 278
Subquery factoring 280
SUBSTR 209
S SUM 165
SYS 21
SAVEPOINT 284 SYSDATE 223
schema 21 SYSTEM 21
Seconda forma normale 417 System Global Area 12
segment 15 System Monitor 12
SELECT 136 System Trigger 365
SELECTINTO 308 SYSTIMESTAMP 223
435
UPDATE 123
T UPPER 213
USER_SOURCE 387
Tabella ASCII 423 utente 21
Tabelle 48 Utenti
Tabelle Index-Organized 54 comuni 402
Table Trigger 58 locali 403
tablespace 14
TCL 281
Teorema di Bohm-Jacopini 295
Teoria degli insiemi 425
V
Complemento 426
Differenza 426 Valori fissi 108
Insieme vuoto 425 Valori Nulli 237
Intersezione 426 VALUE_ERROR 320
Prodotto cartesiano 426 VARCHAR2 68
Sottoinsiemi 425 Variabili 299
Unione 426 VARIANCE 167
TeraByte 422 Varray 333
Terza forma normale 418 Virgola fissa 423
TIMESTAMP 70 Virgola mobile 424
Tipi di dato SQL 67 Viste 55
tnsnames.ora 24 Viste materializzate 56
TO_CHAR 230
TO_DATE 231
TO_NUMBER 231 W
TO_TIMESTAMP 232
TOO_MANY_ROWS 319 WHERE 143
Transazioni 281 WHILE 306
TRANSLATE 217 Windows 420
Trigger 365 WITH 280
Trigger PL/SQL 58 WRAP 389
TRIM 215; 338
TRUNC 219; 227
TRUNCATE 103
Truncate Cascade 104
X
XML DB 59
XMLDATA 141
U XMLDB 59
UNICODE 423
UNION 268
UNION ALL 271
Z
unique key 50
Unix 420 ZERO_DIVIDE 320
UNPIVOT 177
436
Indice delle figure
437
Figura 5-3 Caratteristiche principali di una tabella. ....................................... 50
Figura 5-4 Struttura di un indice B-tree.......................................................... 53
Figura 8-1 Esecuzione del programma PL/SQL in SQL Developer. ........... 296
Figura 8-2 Visualizzazione delloutput in SQL Developer............................ 297
Figura 8-3 Uno script PL/SQL in chiaro ed offuscato. ................................. 389
Figura 9-1 Datafile e Tempfile del PDB ....................................................... 412
438
439