Hey, Scripting Guy!Il ritorno degli script del database

Gli Scripting Guy di Microsoft

Scarica il codice per questo articolo: HeyScriptingGuy2008_04.exe (151KB)

Si sa, se gli Scripting Guy hanno un punto debole (ed è bene sottolineare "se"), è probabilmente questo: si preoccupano troppo delle possibili conseguenze delle azioni che intraprendono. Invece di agire nel proprio interesse, capita in genere che antepongano gli interessi degli altri ai propri, senza prendere in considerazione le possibili conseguenze.

Sono un esempio gli articoli relativi agli script di database. A essere sinceri, gli Scripting Guy ritengono che gli articoli sugli script di database non siano affatto semplici da scrivere. Questo non dipende dalla complessità degli script di database; al contrario, si tratta di script piuttosto semplici. Il problema è che gli Scripting Guy non hanno molte opportunità di lavorare con i database; per questo motivo, ogni volta che si accingono a scrivere articoli sui database, devono fermarsi un momento e pensare alle conseguenze di questa azione. Come si sarà intuito un po' di tempo fa, pensare non è certamente un requisito per diventare Scripting Guy.

In realtà, se avessero mai posseduto la "capacità di pensare", probabilmente gli Scripting Guy non esisterebbero affatto.

Dunque, se la scrittura di articoli sugli script di database risulta così difficoltosa per gli Scripting Guy, perché continuare a scriverli? La risposta è semplice: c'è preoccupazione per ciò che potrebbe succedere al resto del mondo se gli Scripting Guy smettessero di scrivere questi articoli. Quando Sir Arthur Conan Doyle decise di far morire Sherlock Holmes (facendolo cadere da un precipizio nel racconto "Il problema finale"), pensò che si stava semplicemente liberando di un personaggio di cui non voleva più scrivere. Invece, si sollevò un'enorme protesta in tutto il mondo. Secondo alcuni reportage, quando appresero la notizia della sua morte, alcune persone a Londra decisero di indossare il lutto. Il racconto "Il problema finale" fu pubblicato su The Strand Magazine nel 1893; in risposta, 20.000 persone annullarono gli abbonamenti alla rivista.

Ahi!

La preoccupazione degli Scripting Guy è che la decisione di smettere di scrivere articoli sugli script di database potrebbe avere un effetto simile in tutto il mondo. L'idea di diventare causa di cotanta disperazione non è sopportabile e tantomeno lo è l'idea che 20.000 lettori annullino l'abbonamento a TechNet Magazine. Quindi, ecco la buona novella: gli Scripting Guy continueranno a scrivere articoli sugli script di database. Quando? Perché non subito?

Aggiunta di record a un database

Nell'articolo di questo mese verranno illustrati alcuni ingegnosi suggerimenti per l'utilizzo dei database. Questi suggerimenti vengono forniti a complemento dei suggerimenti riportati nell'articolo di settembre 2007 (technetmagazine.com/issues/2007/09/HeyScriptingGuy); persino gli Scripting Guy non si abbassano a scrivere lo stesso articolo due volte.

Bisogna comunque ammettere che l'idea è passata per un attimo per le loro menti.

Allora, si inizia illustrando un metodo semplice per aggiungere un record a un database. Si supponga di disporre di un database, C:\Scripts\Inventory.mdb, con una tabella denominata Computers. La tabella Computers contiene i seguenti campi:

  • ComputerName
  • SerialNumber
  • UserName
  • Department

Come è possibile aggiungere un nuovo computer a questo database? Basta guardare il codice riportato nella Figura 1.

Figure 1 Aggiunta di un record alla tabella Computers

Const adOpenStatic = 3
Const adLockOptimistic = 3

Set objConnection = CreateObject("ADODB.Connection")
Set objRecordSet = CreateObject("ADODB.Recordset")

objConnection.Open _
    "Provider = Microsoft.Jet.OLEDB.4.0; " & _
        "Data Source = C:\Scripts\Inventory.mdb"

objRecordSet.Open "INSERT INTO Computers (ComputerName, SerialNumber, UserName, Department)" &  _
    "VALUES ('atl-ws-07', '11234', 'Ken Myer', 'Finance')", _
        objConnection, adOpenStatic, adLockOptimistic

Le prime righe dello script non verranno trattate nei dettagli; pertanto, chi desidera ottenere informazioni generali in merito a tali righe, può fare riferimento ad alcune delle risorse disponibili in Script Center all'indirizzo microsoft.com/technet/scriptcenter. È sufficiente dire che le costanti adOpenStatic e adLockOptimistic vengono utilizzate per controllare il tipo di cursore e il blocco dei record per il recordset. Contrariamente alle apparenze, si tratta di codice molto semplice. Dopo aver completato la creazione delle istanze degli oggetti ADODB.Connection e ADODB.Recordset, utilizzare il seguente comando per aprire il database:

objConnection.Open _
"Provider = Microsoft.Jet.OLEDB.4.0; " & _
"Data Source = C:\Scripts\Inventory.mdb"

In effetti, questo comando consente di aprire un database di Microsoft® Access® 2003. Per aprire un database di Access 2007, utilizzare il seguente comando:

objConnection.Open _
"Provider = Microsoft.ACE.OLEDB.12.0; " & _
"Data Source = C:\Scripts\Inventory.accdb"

Per aprire invece un database di SQL Server®, è possibile utilizzare un comando simile al seguente:

objConnection.Open _
"Provider=SQLOLEDB;" & _
"Data Source=atl-sql-01;" & _
"Trusted_Connection=Yes;" & _ "InitialCatalog=Inventory;" & _
"User ID=fabrikam\kenmyer;Password=34DE6t4G!;"

Tutto il codice illustrato finora è standard e, come si scoprirà presto, quasi tutti gli script di database iniziano con queste stesse righe di codice. La parte su cui occorre focalizzare l'attenzione è la seguente riga:

objRecordSet.Open _
  "INSERT INTO Computers " & _
  "(ComputerName, SerialNumber, " & _
  "UserName, Department) " & _
    "VALUES ('atl-ws-07', 'A14B1234', " & _
      "'Ken Myer', 'Finance')", _
        objConnection, adOpenStatic, _
        adLockOptimistic

In questa riga viene utilizzata una query INSERT INTO per inserire un nuovo record nella tabella Computers. Dopo il nome della tabella, vengono inclusi i nomi di tutti i campi per i quali si dispone di valori, separando i nomi con virgole e racchiudendoli tutti tra parentesi.

È possibile che il lettore si chieda che cosa intendano dire gli Scripting Guy con la frase "tutti i campi per i quali si dispone di valori". Ottima domanda. Si supponga che al nuovo computer non sia stato ancora assegnato un valore Department. Presupponendo che il database consenta di inserire un valore Null nel campo Department, è possibile non includere Department nell'elenco e non assegnare alcun valore a tale campo. In altre parole, si potrebbe scrivere una query simile alla seguente:

objRecordSet.Open _
  "INSERT INTO Computers " & _
  "(ComputerName, SerialNumber, " & _
  "UserName) " & _
    "VALUES ('atl-ws-07', 'A14B1234', " & _
      "'Ken Myer')", _
        objConnection, adOpenStatic, _
        adLockOptimistic

A proposito dell'assegnazione di valori, attenzione agli elementi che seguono i nomi dei campi: la parola chiave VALUES seguita dai valori che si desidera assegnare a ciascun campo (anch'essi racchiusi tra parentesi). I nomi dei campi possono essere elencati in qualsiasi ordine; ad esempio, è possibile inserire ComputerName per primo, anche nel caso in cui non rappresenti il primo campo del database. Questa è una procedura valida per i nomi dei campi, ma non per i valori. I valori devono essere elencati nello stesso ordine in cui vengono visualizzati i campi. Se il primo campo elencato è ComputerName, il primo valore deve corrispondere al nome del computer. In caso contrario, potrebbero verificarsi dei problemi. Si potrebbe finire, ad esempio, con l'assegnare il nome utente o il numero di serie al campo ComputerName.

Come è possibile osservare, l'assegnazione di valori non è un'attività molto complessa; è sufficiente accertarsi di formattare i valori in base al tipo di dati: le date e i valori stringa devono essere racchiusi tra virgolette singole; i valori numerici e booleani non devono essere racchiusi tra virgolette singole.

Se si dispone di un valore che già prevede una virgoletta singola, come il nome O'Brien, è necessario aggiungere alla virgoletta in questione un carattere di escape, raddoppiandola:

'O''Brien'

È folle, ma vero.

Eliminazione di record da un database

Molto interessante: è possibile aggiungere un record a un database eseguendo una singola query SQL. Esiste qualcosa di meglio al mondo? Agli Scripting Guy non viene in mente altro.

In verità un'eccezione esiste, ed è la possibilità di eliminare più record da un database utilizzando una singola query.

Si supponga che la propria azienda decida di eliminare il reparto Human Resources (no, niente scherzi; gli Scripting Guy già hanno abbastanza problemi con l'ufficio del personale di Microsoft). Come è possibile eliminare tutti i computer Human Resources dal database Inventory? Nella Figura 2 viene illustrato un metodo per eseguire questa operazione.

Figure 2 Eliminazione di più record

Const adOpenStatic = 3
Const adLockOptimistic = 3

Set objConnection = CreateObject("ADODB.Connection")
Set objRecordSet = CreateObject("ADODB.Recordset")

objConnection.Open _
    "Provider = Microsoft.Jet.OLEDB.4.0; " & _
        "Data Source = C:\Scripts\Inventory.mdb"

objRecordSet.Open "DELETE * FROM Computers Where Department='Human Resources'", _
    objConnection, adOpenStatic, adLockOptimistic

Come si può osservare, questo specifico script inizia esattamente come lo script per l'aggiunta di un nuovo record: definizione di alcune costanti, creazione di due oggetti e connessione al database Inventory.mdb. In seguito, è sufficiente utilizzare una query DELETE per eliminare tutti i record (*) dalla tabella Computers o almeno tutti i record in cui il campo Department è impostato su Human Resources:

objRecordSet.Open _
  "DELETE * FROM Computers " & _
   "Where Department='Human Resources'", _
    objConnection, adOpenStatic, _
    adLockOptimistic

È semplice quanto cadere in un precipizio.

Senza offesa, Sherlock Holmes.

Aggiornamento di record in un database

Senza dubbio, tutti i lettori concorderanno che sarebbe davvero divertente riuscire a eliminare tutte le tracce del proprio ufficio del personale. Nota per l'ufficio del personale Microsoft: naturalmente sarebbe divertente per altre aziende e il relativo reparto. Non per noi. Gli Scripting Guy non ne trarrebbero alcun piacere personale. Tuttavia, l'eliminazione di tutti i computer HR dal database Inventory potrebbe non essere la migliore cosa da fare. Perché no? In effetti, a meno che i dipendenti dell'ufficio del personale non siano scappati con tutto l'hardware (evento comunque da non escludere), tali computer restano ancora proprietà dell'azienda, il che significa che i computer devono essere comunque riportati nel database. Premesso questo, si può procedere con le seguenti operazioni. Invece di eliminare i record dal database, aggiornare semplicemente ciascun record; il nome del reparto per ciascun computer verrà modificato da Human Resources a None. In altre parole, verrà eseguito lo script illustrato nella Figura 3.

Figure 3 Aggiornamento di record

Const adOpenStatic = 3
Const adLockOptimistic = 3

Set objConnection = CreateObject("ADODB.Connection")
Set objRecordSet = CreateObject("ADODB.Recordset")

objConnection.Open _
    "Provider = Microsoft.Jet.OLEDB.4.0; " & _
        "Data Source = C:\Scripts\Inventory.mdb"

objRecordSet.Open "UPDATE Computers Set Department = 'None' " & _
    "Where Department = 'Human Resources'", _
    objConnection, adOpenStatic, adLockOptimistic

L'unico elemento di diversità in questo script è la query SQL. In questo caso, viene utilizzata una query UPDATE per aggiornare i record nella tabella Computers. Oltre alla parla chiave UPDATE, è necessario aggiungere due parametri che indicano alla query come aggiornare i record e quali record aggiornare:

  • Set Department = 'None'. Con questa impostazione si specifica semplicemente il nuovo valore per il campo Department. È possibile impostare contemporaneamente più valori di campo utilizzando la seguente sintassi: Set Department = 'None', UserName = 'None'. Come è possibile osservare, i campi Department e UserName vengono impostati entrambi su None.
  • Where Department = 'Human Resources'. Questa è una clausola Where standard che indica quali record aggiornare; in questo caso occorre aggiornare tutti i record il cui campo Department sia impostato su Human Resources. L'operazione viene eseguita per un motivo semplice: l'obiettivo non è modificare tutti i record del database, ma solo i record (computer) che in precedenza appartenevano al reparto Human Resources.

Di seguito viene illustrata un'attività molto interessante che è possibile eseguire con le query Update. Si supponga che la propria azienda abbia deciso di dare a ogni dipendente un aumento del 10% (gli Scripting Guy hanno in comune con Sir Arthur Conan Doyle almeno un aspetto: negli scritti entrambi esplorano i meandri più remoti della fantasia). Di seguito è riportato uno script che consente di aprire una tabella denominata Employees e di modificare il campo Salary per ciascun dipendente. Su quale valore viene impostato il campo Salary? La query consente di impostare questo campo sullo stipendio corrente del dipendente x 1,1; in altre parole, offre a ogni dipendente un aumento del 10% (magari fosse così semplice)! Ecco la query:

objRecordSet.Open _
  "Update Employees " & _
  "Set Salary = (Salary * 1.1)", _
    objConnection, adOpenStatic, _
    adLockOptimistic

L'aspetto interessante? Come si può vedere, è possibile eseguire i calcoli nelle query Update. Nel caso in cui si sia deciso di estendere il contratto per tutti i dipendenti temporanei per altri 60 giorni, può essere utile utilizzare una query simile alla seguente:

objRecordSet.Open _
  "Update TempEmployees " & _
  "Set ContractExpirationDate = " & _
  "(ContractExpirationDate + 60)", _
    objConnection, adOpenStatic, _
    adLockOptimistic

Metodi interessanti per il recupero dei dati

A proposito di query che potrebbero rivelarsi utili, è opportuno esaminare alcuni interessanti metodi per il recupero di dati da un database. Di seguito viene riportato uno script semplice ma molto utile. Si supponga che il database Inventory contenga un campo denominato Price, un campo che, ovviamente, rappresenta il prezzo del computer. Si desidera sapere quali sono i cinque computer più costosi all'interno dell'organizzazione? A tal fine, dare un'occhiata allo script di esempio nella Figura 4.

Figure 4 Ordinamento del recordset

Const adOpenStatic = 3
Const adLockOptimistic = 3

Set objConnection = CreateObject("ADODB.Connection")
Set objRecordSet = CreateObject("ADODB.Recordset")

objConnection.Open _
    "Provider = Microsoft.Jet.OLEDB.4.0; " & _
        "Data Source = C:\Scripts\Test.mdb" 

objRecordSet.Open "SELECT Top 5 * FROM Computers Order By Price", _
     objConnection, adOpenStatic, adLockOptimistic

objRecordSet.MoveFirst

Do Until objRecordset.EOF
    Wscript.Echo objRecordset.Fields.Item("ComputerName")
    objRecordset.MoveNext
Loop

objRecordSet.Close
objConnection.Close

In questa query SQL sono state eseguite due operazioni: il recordset è stato ordinato in base al prezzo (Order By Price) e si è richiesto solo il prezzo dei primi cinque computer più costosi; questa è la funzione svolta da SELECT Top 5. Se avessimo desiderato un elenco dei 10 computer più costosi, sarebbe stato necessario utilizzare la seguente query:

objRecordSet.Open _
  "SELECT Top 10 * FROM Computers " & _
  "Order By Price", _
    objConnection, adOpenStatic, _
    adLockOptimistic

Notare inoltre che è stato aggiunto il codice necessario per scorrere in ciclo il recordset e visualizzare il nome di ciascun computer. Questo codice non è stato necessario negli script precedenti, poiché questi non prevedevano la restituzione e la visualizzazione di dati.

In alternativa, è possibile ottenere il 10% dei computer più costosi utilizzando la seguente query:

objRecordSet.Open _
  "SELECT Top 10 PERCENT * " & _
  "FROM Computers Order By Price", _
    objConnection, adOpenStatic, _
    adLockOptimistic

Se invece desiderassimo visualizzare i computer più economici? Nessun problema; occorre utilizzare lo stesso approccio, con la differenza che questa volta il recordset verrà elencato in ordine decrescente, ovvero dal prezzo più basso al prezzo più alto. In altre parole, si utilizzerà la seguente query, in cui DESC indica che il recordset deve essere elencato in ordine decrescente:

objRecordSet.Open _
  "SELECT Top 5 * FROM Computers " & _
  "Order By Price DESC", _
    objConnection, adOpenStatic, _
    adLockOptimistic

Visto? Queste query sono davvero utili.

Ecco altre due query molto interessanti. Si supponga che il database contenga un campo denominato Budgeted che tiene traccia dell'importo preventivato in origine per il computer. Si desidera operare un confronto tra il costo effettivo e l'importo preventivato? La seguente query restituisce un elenco di computer con un costo superiore all'importo preventivato:

objRecordSet.Open _
  "SELECT * FROM Computers " & _
  "Where (Budgeted < Price)", _
    objConnection, adOpenStatic, _
    adLockOptimistic

Allo stesso tempo, la query calcola il prezzo medio di tutti i computer (SELECT AVG(Price) FROM Computers), quindi restituisce un elenco di tutti i computer con un costo inferiore al prezzo medio:

objRecordSet.Open _
  "SELECT * FROM Computers " & _
  "WHERE Price < " & _
  "(SELECT AVG(Price) FROM Computers)", _
    objConnection, adOpenStatic, _
    adLockOptimistic

Come è facile notare, nella clausola Where si è utilizzata una query SELECT. Come funziona esattamente? Questo è un argomento da affrontare in un'altra occasione. Tuttavia, rappresenta il primo passo per il recupero di ogni sorta di informazione mediante l'uso di query SQL.

Morale della favola

Come evidenziato all'inizio dell'articolo di questo mese, gli Scripting Guy erano un po' riluttanti a scrivere un altro articolo sugli script di database. Tuttavia, ora sono soddisfatti di averlo scritto, in parte perché contiene alcune query di grande utilità, ma anche per il seguente motivo: se non l'avessero scritto ora, l'avrebbero scritto lo stesso prima o poi. Dopotutto, persino Sir Arthur Conan Doyle fu costretto a "resuscitare" Sherlock Holmes. I primi tentativi di Sir Arthur in tal senso si hanno con la pubblicazione di nuovi racconti su Sherlock Holmes che narravano episodi precedenti alla morte del detective. Dopo tutto, l'autore aveva semplicemente ceduto alla pressione dei suoi lettori, architettando una storia poco credibile in cui spiegava che Sherlock Holmes aveva simulato la propria morte. Così, tutti erano contenti e ogni cosa era assolutamente perfetta.

L'aspetto interessante è che, quando furono pubblicate le avventure più recenti di Sherlock Holmes, 30.000 nuovi lettori sottoscrissero un abbonamento alla rivista The Strand Magazine. Gli editori di Sir Arthur in Gran Bretagna e negli Stati Uniti risposero rendendolo l'autore più pagato al mondo.

Hmmm, Sir Arthur Conan Doyle ha fatto resuscitare un personaggio amatissimo ed è diventato lo scrittore più pagato al mondo; allo stesso modo, gli Scripting Guy hanno fatto "resuscitare" un argomento molto amato, ma senza simulare alcuna morte. I bravi ragazzi di TechNet Magazine lo avranno notato?

Il rompicapo di script del Dottor Scripto

La sfida mensile che verifica non solo le tue capacità di risoluzione dei puzzle, ma anche le tue competenze di scripting.

Aprile 2008: scelta di una lettera

Nel puzzle di questo mese, è necessario inserire le lettere da A a O negli spazi blu per ottenere il nome di una funzione VBScript. Ogni lettera (da A a O) deve essere utilizzata una sola volta e le lettere non sono visualizzate in ordine alfabetico. La lettera può essere inserita all'inizio del nome della funzione, alla fine del nome della funzione o in una posizione qualsiasi all'interno del nome di una funzione. Ad esempio, nella riga seguente la lettera D viene inserita per completare il nome della funzione IsDate:

  (Fare clic sull'immagine per ingrandirla)

Ora, prova a inserire le lettere da A a O per ottenere i nomi delle funzioni VBScript in questa griglia:

**** (Fare clic sull'immagine per ingrandirla)

ANSWER:

Il rompicapo di script del Dottor Scripto

Risposta: scelta di una Lettera, aprile 2008

  (Fare clic sull'immagine per ingrandirla)

Gli Scripting Guy di Microsoft lavorano o, per meglio dire, sono stipendiati da Microsoft. Quando non si dedicano al baseball (o ad altre attività) come giocatori, allenatori o semplici spettatori, gestiscono il TechNet Script Center. Consultare la pagina www.scriptingguys.com.

© 2008 Microsoft Corporation e CMP Media, LLC. Tutti i diritti riservati. È vietata la riproduzione completa o parziale senza autorizzazione.