dicembre 2008 - Posts
L'oggetto DataTable, tra i suoi metodi, c'è ne uno che permette di fare delle query. Il metodo Select, accetta due argomenti, il secondo è facoltativo, il primo è la query, ossia il valore da ricercare in un determinato campo, mentre il secondo è l'ordinamento.
Di seguito si riporta un frammento di codice, di utilizzo del metodo select della classe DataTable, in particolare si effettua una ricerca nel campo nome, con il valore Emanuele. Si nota, che è possibile utilizzare anche l'operatore like.
VB.Net
Dim con As String = "Data Source=(local);Integrated Security=SSPI; Initial Catalog=test"
Dim Sql As String = "Select * from Dati "
Try'
Dim DtaDati As New SqlDataAdapter(Sql, con)
Dim DttDati As New DataTable("Dati")
DtaDati.Fill(DttDati)
'posso utilizzare anche la likeDim riga() As DataRow = DttDati.Select("Nome = 'Emanuele'")
If riga.Length < 1 ThenMessageBox.Show("Nessun record")
ElseMessageBox.Show("Record esistente")End If
Catch ex As ExceptionMessageBox.Show("Errore:" & ex.Message)
End Try
C#
string con = "Data Source=(local);Integrated Security=SSPI; Initial Catalog=test";
String Sql = "Select * from Dati where id = 1";
try
{
SqlDataAdapter DtaDati = new SqlDataAdapter(Sql, con);DataTable DttDati = new DataTable("Dati");
DtaDati.Fill(DttDati);
// posso utilizzare anche la likeDataRow[] riga = DttDati.Select("Nome = 'Emanuele'");if (riga.Length < 1)
{
MessageBox.Show("Nessun record");
}
else
{
MessageBox.Show("Record esistente");
}
}
catch (Exception ex)
{
MessageBox.Show("Errore: " + ex.Message);
}
Il seguente code snippet, illustra l'utilizzo del metodo find, della classe datatable, per trovare un determinato record. Va ricordato che tale metodo, si utilizza, solo nel caso che la colonna abbia valori univoci e non dupplicati.
L'esempio qui proposto è per il linguaggio di programmazione VB.Net e C#
VB.Net
Dim con As String = "Data Source=(local);Integrated Security=SSPI; Initial Catalog=test"
Dim Sql As String = "Select * from Dati "
Try'
Dim DtaDati As New SqlDataAdapter(Sql, con)
Dim DttDati As New DataTable("Dati")
DtaDati.Fill(DttDati)
'solo per valori univoci. Altrimenti erroreDttDati.PrimaryKey = New DataColumn() {DttDati.Columns("Nome")}
'rilevo i datiDim riga As DataRow = DttDati.Rows.Find("emanuele")
If riga IsNot Nothing ThenMessageBox.Show("Record esistente")
ElseMessageBox.Show("Nessun record")End If
Catch ex As ExceptionMessageBox.Show("Errore:" & ex.Message)
End Try
C#
string con = "Data Source=(local);Integrated Security=SSPI; Initial Catalog=test";
String Sql = "Select * from Dati where id = 1";
try
{
SqlDataAdapter DtaDati = new SqlDataAdapter(Sql, con);DataTable DttDati = new DataTable("Dati");
DtaDati.Fill(DttDati);
//solo per valori univoci. Altrimenti erroreDttDati.PrimaryKey = new DataColumn[]{DttDati.Columns["Nome"]};
//rilevo i datiDataRow riga = DttDati.Rows.Find("emanuele");if (riga != null)
{
MessageBox.Show("Record esistente");
}
else
{
MessageBox.Show("Nessun record");
}
}
catch (Exception ex)
{
MessageBox.Show("Errore: " + ex.Message);
}
Per coloro che sono interessati a provare la versione in italiano di Microsoft Sql Server 2008 Enterprise, segnalo due interessati siti dove poter scaricare la versione trial di 180 giorni (ben 6 mesi).
Dal seguente sito http://www.microsoft.com/downloads/details.aspx?FamilyID=6b10c7c1-4f97-42c4-9362-58d4d088cd38&DisplayLang=it potete scaricare la versione per sviluppatori, mentre dal seguente sito http://www.microsoft.com/downloads/details.aspx?FamilyID=265f08bc-1874-4c81-83d8-0d48dbce6297&DisplayLang=it per professionisti IT.
Per maggiori informazioni e download visitate i siti indicati.
La classe SqlDataAdapter, tramite il metodo update, permette l'aggiornamento dei dati, quando si esegue tale metodo si scatenano vari eventi, tra cui RowUpdating, il quale è il momento in cui si sta facendo l'aggiornamento dei dati.
L'esempio di codice, qui di seguito, illustra come tramite il linguaggio VB.Net e C#, possiamo gestire tale evento.
VB.Net
Dim con As String = "Data Source=(local);Integrated Security=SSPI; Initial Catalog=test"
Dim Sql As String = "Select * from Dati where id = 1 "
Try'
Dim DtaDati As New SqlDataAdapter(Sql, con)
Dim cmbDati As New SqlCommandBuilder(DtaDati)Dim DttDati As New DataTable("Dati")
'gestore dell'evento RowUpdatingAddHandler DtaDati.RowUpdating, AddressOf DtaDati_RowUpdating
DtaDati.Fill(DttDati)
'aggiorno il dato
DttDati.Rows(0)(
"nome") = DttDati.Rows(0)("nome") & " Nuovo"
'metodo che aggiorna il dato
DtaDati.Update(DttDati)
Catch ex As ExceptionMessageBox.Show("Errore:" & ex.Message)
End Try
'Funzione per la gestione dell'evento RowUpdating, si scatena, quando l'aggiornamento si sta verificandoPrivate Sub DtaDati_RowUpdating(ByVal sender As Object, ByVal e As SqlRowUpdatingEventArgs)
If e.Status = UpdateStatus.ErrorsOccurred ThenMessageBox.Show("Errore")
ElseMessageBox.Show("Evento: " & e.StatementType.ToString())
MessageBox.Show(
"Valore da - a " & e.Row("nome", DataRowVersion.Original) + " - " + e.Row("nome"))
End IfEnd Sub
C#
string con = "Data Source=(local);Integrated Security=SSPI; Initial Catalog=test";
String Sql = "Select * from Dati where id = 1";
try
{
SqlDataAdapter DtaDati = new SqlDataAdapter(Sql, con);
SqlCommandBuilder cmbDati = new SqlCommandBuilder(DtaDati);
//gestore dell'evento RowUpdatingDtaDati.RowUpdating += new SqlRowUpdatingEventHandler(DtaDati_RowUpdating);DataTable DttDati = new DataTable("Dati");
DtaDati.Fill(DttDati);
//aggiorno il datoDttDati.Rows[0]["nome"] = DttDati.Rows[0]["nome"] + " Nuovo";
//metodo che aggiorna il dato
DtaDati.Update(DttDati);
}
catch (Exception ex)
{
MessageBox.Show("Errore: " + ex.Message);
}
//Funzione per la gestione dell'evento RowUpdating, si scatena, quando l'aggiornamento si sta verificandovoid DtaDati_RowUpdating(object sender, SqlRowUpdatingEventArgs e)
{
if (e.Status == UpdateStatus.ErrorsOccurred)
{
MessageBox.Show("Errore");
}
else
{
MessageBox.Show("Event: " + e.StatementType);MessageBox.Show("Valore da - a " + e.Row["nome", DataRowVersion.Original] + " - " + e.Row["nome"]);
}
}
La classe SqlDataAdapter, tramite il metodo update, aggiorna i dati di una fonte dati sql server tramite il metodo Update. Al termine dell'aggiornamento, si scatena un evento (rowupdated) . L'esempio qui di seguito, illustra come creare un gestore di evento per tale evento.
VB.Net
Dim con As String = "Data Source=(local);Integrated Security=SSPI; Initial Catalog=test"
Dim Sql As String = "Select * from Dati "
Try'
Dim DtaDati As New SqlDataAdapter(Sql, con)
Dim cmbDati As New SqlCommandBuilder(DtaDati)Dim DttDati As New DataTable("Dati")
'gestore dell'evento rowupdatedAddHandler DtaDati.RowUpdated, AddressOf DtaDati_RowUpdated
DtaDati.Fill(DttDati)
'aggiorno il dato
DttDati.Rows(0)(
"nome") = DttDati.Rows(0)("nome") & " Nuovo"
'metodo che aggiorna il dato
DtaDati.Update(DttDati)
Catch ex As ExceptionMessageBox.Show("Errore:" & ex.Message)
End Try
'Funzione per la gestione dell'evento RowUpdate, si scatena, quando l'aggiornamento Š avvenutoPrivate Sub DtaDati_RowUpdated(ByVal sender As Object, ByVal e As SqlRowUpdatedEventArgs)
If e.Status = UpdateStatus.ErrorsOccurred ThenMessageBox.Show("Errore")
ElseMessageBox.Show("Evento: " & e.StatementType.ToString())
MessageBox.Show(
"Valore modificato " & e.Row("nome").ToString())
End IfEnd Sub
C#
string con = "Data Source=(local);Integrated Security=SSPI; Initial Catalog=test";
String Sql = "Select * from Dati where id = 1";
try
{
SqlDataAdapter DtaDati = new SqlDataAdapter(Sql, con);
SqlCommandBuilder cmbDati = new SqlCommandBuilder(DtaDati);
//gestore dell'evento rowupdatedDtaDati.RowUpdated += new SqlRowUpdatedEventHandler(DtaDati_RowUpdated);DataTable DttDati = new DataTable("Dati");
DtaDati.Fill(DttDati);
//aggiorno il datoDttDati.Rows[0]["nome"] = DttDati.Rows[0]["nome"] + " Nuovo";
//metodo che aggiorna il dato
DtaDati.Update(DttDati);
}
catch (Exception ex)
{
MessageBox.Show("Errore: " + ex.Message);
}
//Funzione per la gestione dell'evento RowUpdate, si scatena, quando l'aggiornamento Š avvenuto
void DtaDati_RowUpdated(object sender, SqlRowUpdatedEventArgs e)
{
if (e.Status == UpdateStatus.ErrorsOccurred)
{
MessageBox.Show("Errore di aggiornamento");
}
else
{
MessageBox.Show("Evento: " + e.StatementType);MessageBox.Show("Valore modificato " + e.Row["nome"].ToString());
}
}
Vi segnalo questo http://blogs.msdn.com/blakhani/archive/2008/12/27/resources-migration-from-sql-2000-sql2005-to-sql-2008.aspx interessante post, nel quale sono riportati siti a delle risorse per la migrazione del database sql server 2000 o 2005 alla nuova versione di Sql Server 2008.
Buona lettura :-)))
Quando si utilizza il metodo fill, della classe SqlDataAdapter, possiamo crearci un gesto di evento, per gestire l'eventualità di un errore.
In questo esempio di codice, (VB.Net e C#) vediamo un esempio pratico. L'errore, voluto, riguarda la mancata creazione di colonne nell'oggetto datatable.
VB.Net
'Esempio dell'evento FillError, si verifica nel caso ci sono errori durante l'utilizzo del metodo fill
Dim con As String = "Data Source=(local);Integrated Security=SSPI; Initial Catalog=test"
Dim Sql As String = "Select * from Dati where id = 'a'"
Try'
Dim DtaDati As New SqlDataAdapter(Sql, con)
DtaDati.MissingSchemaAction = MissingSchemaAction.Error
Dim DttDati As New DataTable("Dati")
'gestore dell'evento fill errorAddHandler DtaDati.FillError, AddressOf DtaDati_FillError
DtaDati.Fill(DttDati)
Catch ex As ExceptionMessageBox.Show("Errore:" & ex.Message)
End TryPublic Sub DtaDati_FillError(ByVal sender As Object, ByVal e As FillErrorEventArgs)
MessageBox.Show(e.Errors.Message)
e.Continue =
True
End Sub
C#
//Esempio dell'evento FillError, si verifica nel caso ci sono errori durante l'utilizzo del metodo fillstring con = "Data Source=(local);Integrated Security=SSPI; Initial Catalog=test";
String Sql = "Select * from Dati where id = 1";
try
{
SqlDataAdapter DtaDati = new SqlDataAdapter(Sql, con);
DtaDati.MissingSchemaAction =
MissingSchemaAction.Error;DataTable DttDati = new DataTable();
//gestore dell'evento fill errorDtaDati.FillError += new FillErrorEventHandler(DtaDati_FillError);
//non valorizzando con i nomi delle colonne genero un eccezione.
DtaDati.Fill(DttDati);
}
catch (Exception ex)
{
MessageBox.Show("Errore: " + ex.Message);
}
//gestore di evento
void DtaDati_FillError(object sender, FillErrorEventArgs e)
{
MessageBox.Show(e.Errors.Message);
e.Continue =
true;
}
Da qualche settimana è stata data la possibilità a tutti, di scaricare gratuitamente http://csna01.libredigital.com/?urss1q2we6, in formato pdf, il manuale Introducing Microsoft Sql Server 2008, un manuale in lingua inglese riguardante l'utilizzo della nuova versione del database Microsoft Sql Server 2008.
Il libro è scritto da tre esperti del settore, ossia da Peter De Betta, Greg Low, e Mark Whitehorn, i quali con i loro anni ed anni di esperienze, illustrano in maniera professionale, questa nuova versione del database Microsoft. Questo manuale è composto da 7 capitoli, per un totale di circa 260 pagine, adatto sia a coloro che utilizzano la versione precedente di questo database, e quindi sono interessanti ad approffondire alcuni aspetti di questa nuova versione e sia a coloro che stanno pensando di passare a questo ottimo database, in cui in quest'ultimi anni si è fatto molto apprezzare per la sicurezza e qualità offerte.
Va vediamo in dettaglio i vari capitoli del libro.
Nel primo capitolo si passa alla sicurezza ed all'amministrazione del database, dopo una valida introduzione, si passa ad esempi di codice, per la gestione delle policy ed autorizzazioni. I vari script, tutti in T-SQL, guideranno il lettore alla configurazione del database e grazie alle innumerevoli immagini, il lettore non avrà difficoltà a comprendere l'argomento che si sta trattando.
Il secondo capitolo riguarda le prestazioni, infatti ogni database che si rispetti, dev'essere non solo normalizzato, ma anche impostato con determinate configurazioni per rispondere in modo corretto alle esigenze delle applicazioni che ne faranno uso. L'importanza di un Database configurato con determinate impostazioni, può migliorare notevolmente anche l'attività delle applicazioni, sia di tipo Web, e sia di tipo Windows application. Un vero dba, che si rispetti, sa che per ottenere degli ottimi risultati, non contano soltato la buona stesura di Store Procedure, ma anche il modo di come creare e gestire il database, del carico del lavoro che dovrà subire. In questo capitolo viene illustrato proprio come rendere il database con ottime prestazioni, oltre agli esempi di codice ed immagini, troviamo anche tabelle riassiuntive, per fornire una valido schema dei vari scenari che si possono verificare. La gestione della comprenssione dei dati, dei backup, partizioni, ed altro ancora, sono aspetti che ogni DBA, devo conoscere, per rendere agli sviluppatori un base dati rispondente alle esigenze di applicazioni complesse. Nella parte finale di questo capitolo, troviamo numerosi esempi di codice T-SQL, per mostrare l'utilizzo di alcune funzionalità offerte dal database Sql Server 2008 per la gestione delle prestazioni.
Nel terzo capitolo, si passa ai tipi di dato offerti dal sistema di questo valido database. Dopo una breve introduzione sui tipi di dato, si pasa ad esempio di codice, anche in questo caso tramite il linguaggio T-SQL. La gestione degli indici e l'utilizzo dell'elemento HierarchyID ed il formato XML. Argomenti interessanti per coloro che devono amministratore il database. Il lettore leggendo questo capitolo, comprenderà l'importanza della creazione delle tabelle, con i dovuti accorgimenti, utilizzando in modo corretto i tipi di dati, gli indici ed altro ancora in modo corretto ed ottimale.
Il quarto capitolo, riguarda un tema molto interessante, la programmazione del database, in fatti coloro che utilizzano questo database, non devono solo conoscere la parte di configurazione, ma anche l'aspetto di programmazione.
In questo capitolo, vedremo l'utilizzo di T-SQL, l'utilizzo del merge per eseguire più operazioni alla volta, la clausola Where per specificare la condizione di ricerca, ed altre interessanti parole chiavi, un capitolo dove si trovano tantissimi esempi di codice.
Con il database SQL Server 2005, è stata introdotta una novità molto interessanti, per gli sviluppatori .Net, la possibilità di scrivere codice .Net, tramite il lnguaggio Visual Basic Net o C#, proprio nel database. In questo capitolo, vedremo qualche esempio di codice in questa nuova versione del database.
Nel quinto capitolo, si passa alla creazione di Viste e Tabelle, per una migliore gestione della quantità di dati di archiaviazione. Il capitolo a differenza dei precendenti è molto breve, giusto per offirire una valida e breve introduzione a questo tema.
Nel penultimo capitolo, ossia il sesto, vengono forniti al lettore, le basi, per la creazione di un sistema per la gestione dei carichi di lavoro. Nelle prime pagine, viene fornita al lettore, le caratteristiche hardware, la gestione delle partizioni, ed altro che possono compromettere o mgliorare le prestazioni di questo Database. Il capitolo è molto breve.
Con il settimo e ultimo capitolo del libro, si passa all'utilizzo del database Sql Server 2008, riguardante lo scenerio di Business Intelligence, scenario sempre più comune nel settore IT. In questo capitolo vedremo aspetti interessanti, come la gestione di Reporting Services, Integration Services e Analysis Services. Tramite le numerose immagini, il lettore verrà guidato passo dopo passo, in questi argomenti, e sarà in grado di muoversi in piena autonomina su un tema molto importante.
Elenco dei capitoli.
1) Security and Administrator
2) Performance
3) Type System
4) Programmability
5) Storage
6) Enchancements for high availability
7) Business Intelligence Enchancements
Conclusioni:
Un ottimo libro, che offre interessanti contenuti, molto indicato a coloro che sono interessati a questa nuova versione e che provvengono dalla versione precedente o che sono interessati a questo database. Si consiglia la lettura non solo a coloro che devono amministrare il database, ma anche a coloro che sviluppano applicazioni, tra l'altro questa versione elettronica si può scaricare gratuitamente dal seguente indirizzo web http://csna01.libredigital.com/?urss1q2we6 .

Eccoci giunti al grnde giorno, un giorno particolare ed importante. Il natale e la fine dell'anno.
Devo ammetterlo, quest'anno è andato proprio bene, raggiunti tutti gli obiettivi, e qualcuno in più che non mi aspettavo, certo quello più importante e difficile, no, ma tenterò per il prossimo anno. Vediamo un pò.
Questa'anno ho imparato molte cose, sono maturato come uomo, e mi ha fatto tanto, ma tanto piacere aver conosciute diverse persone, un viaggio dove ho fatto diverse esperienze, e non solo personali ma anche lavorative.
Mi auguro che anche il prossimo anno, sia come quest'anno, e magari con la conquista più cercata ;-).
Un grazie particolare, anche all'amico Luca http://community.ugiss.org/blogs/lbianchi/default.aspx che quest'anno mi ha fatto un bellissio regalo, ma ciò che mi ha colpito di più è il suo modo di essere, la persona che è, un grande uomo.
Ringranzio tutti, amici del web e quelli che ogni giorno stanno con me, e l'augurio di un anno migliore, con più amore e serenità, sperando che la gente, comprenda che basta fare poco per avere un mondo migliore.
Vi auguro un bellissimo natale e che l'anno nuovo vi porti tanta felicità.
L'augurio dal vostr blogger Emanuele ;-)).
P.S. Incredibile, anche quest'anno ho inserito il post degli aguri lo stesso giorno di quello dello scorso anno. http://blog.shareoffice.it/emanuele/archive/2007/12/23/9388.aspx :-)))
Con Ado.Net versione 2 o successiva, possiamo eseguire più batch su una singola connessione. Nelle versioni precedenti era possibile eseguire un batch alla volta su una singola connessione. L'esecuzione di più batch con MARS non implica l'esecuzione simultanea delle operazioni.
Questo avviene impostando nella connectionstring il parametro MultipleActiveResultSets a true.
Es.
MultipleActiveResultSets=True
Qui di seguito si riporta un frammento di codice.
VB.Net
Dim con As String = "Data Source=(local);Integrated Security=SSPI; Initial Catalog=test; MultipleActiveResultSets=True"Using ConDati As New SqlConnection(con)
Dim SqlTabDati As String = "Select id from Dati"
Dim SqlTabAnagrafica As String = "Select * from Anagrafica where id = @id"Dim DatiCmd As SqlCommand
Dim AnagraficaCmd As SqlCommand
TryDatiCmd = New SqlCommand(SqlTabDati, ConDati)
AnagraficaCmd =
New SqlCommand(SqlTabAnagrafica, ConDati)AnagraficaCmd.Parameters.Add("@id", SqlDbType.Int)
ConDati.Open()
Dim idDati As IntegerUsing DatiReader = DatiCmd.ExecuteReader()
While DatiReader.Read()idDati = CInt(DatiReader("id"))
AnagraficaCmd.Parameters(
"@id").Value = idDatiUsing AnagraficaReader As SqlDataReader = AnagraficaCmd.ExecuteReader()
While AnagraficaReader.Read()MessageBox.Show("Dati: " & AnagraficaReader("nazione"))
End WhileEnd Using
End WhileEnd Using
Catch exdb As SqlException
MessageBox.Show(
"ERrore:" & exdb.Message)
ReturnCatch ex As Exception
MessageBox.Show(
"ERrore:" & ex.Message)
Return
End Try
ConDati.Close()
End Using
C#
string con = "Data Source=(local);Integrated Security=SSPI; Initial Catalog=test; MultipleActiveResultSets=True";using (SqlConnection ConDati = new SqlConnection(con))
{
string SqlTabDati = "Select id from Dati";string SqlTabAnagrafica = "Select * from Anagrafica where id = @id";
SqlCommand DatiCmd;SqlCommand AnagraficaCmd;
try
{
DatiCmd = new SqlCommand(SqlTabDati, ConDati);
AnagraficaCmd =
new SqlCommand(SqlTabAnagrafica, ConDati);AnagraficaCmd.Parameters.Add("@id", SqlDbType.Int);
ConDati.Open();
SqlDataReader DatiReader;
int idDati;using (DatiReader = DatiCmd.ExecuteReader())
{
while (DatiReader.Read())
{
idDati = (int)(DatiReader["id"]);
AnagraficaCmd.Parameters[
"@id"].Value = idDati;using (SqlDataReader AnagraficaReader = AnagraficaCmd.ExecuteReader())
{
while (AnagraficaReader.Read())
{
MessageBox.Show("Dati: " + AnagraficaReader["nazione"]);
}
}
}
}
}
catch (SqlException exdb)
{
MessageBox.Show("ERrore:" + exdb.Message);return;
}
catch (Exception ex)
{
MessageBox.Show("ERrore:" + ex.Message);return;
}
ConDati.Close();
}
Interessante questo post http://blogs.msdn.com/blogdoezequiel/archive/2008/12/17/sql-best-practices-for-moss.aspx che illustra delle buone tecniche, da mettere in pratica, qualora si utilizza il database Sql Server e Microsoft Office Sharepoint Server.
Consiglio di dare una letta, per coloro che utilizzano il portale Sharepoint 2007.
Che dirvi... buona lettura :-)))
Da questo sito http://www.microsoft.com/downloads/details.aspx?FamilyID=8c873841-61a1-444c-a40b-ab62cf136be8&DisplayLang=it osi può scaricare un nuovo aggioarnamento di Microsoft Sql Server 2005 per l'applicativo Microsoft Office 2007.
Riporto la descrizione di tale componente:
I componenti aggiuntivi Data mining di SQL Server 2005 per Office 2007. Questo pacchetto include due componenti aggiuntivi per Microsoft Office Excel 2007 (Strumenti di analisi tabelle e Client di data mining) e un componente aggiuntivo per Microsoft Office Visio 2007 (Modelli di data mining).
Per chi utilizza Microsoft Sharepoint 2007, dal seguente sito http://www.microsoft.com/downloads/details.aspx?FamilyID=0acb75a6-7c1d-4e2b-af69-7e5f9ecad299&DisplayLang=it può scaricare un nuovo aggiornamento.
In particolare il componente di utilizzare le funzionalità di gestione ed elaborazione dei report di SQL Server 2005 Service Pack 3 (SP3) all'interno di Windows SharePoint Services 3.0 o Microsoft Office SharePoint Server 2007.
Per il download e maggiori informazioni visitate il sito indicato.
Per chi utilizza la versione Express di Microsoft Sql Server, da questo sito http://www.microsoft.com/downloads/details.aspx?FamilyID=5d76230d-580d-4874-8c7d-93491a29db15&DisplayLang=it può scaricare un nuovo aggiornamento riguardante la service pack 3 del tools per la gestione del database Sql Server 2005 express.
More Posts
Next page »