N342 Database/ADO

Modified

Basics

Databases are one key component of most Web systems and can easy be generically accessed from ASP using the ADO (ActiveX Data Objects) technology. We will examine the combination of ASP, Access databases, ADO, and SQL to produce database driven pages.

Databases

Relational databases from nearly any vendor can be manipulated using the SQL language, that includes Access and Microsoft SQL Server. On an IIS Web server (and many others) the ADO (ActiveX Data Objects) provide a simple means of connecting to an SQL compliant database, issuing SQL commands to create, delete, retrieve or modify parts of the database. Essentially anything that can be expressed in SQL can by performed by a server-side application (e.g. ASP).

ADO can provide a simple, generic means of database use but the nuances are very complex. The examples given here will generally work for our purposes but are not intended for every application.

Microsoft Access

Relational databases such as Access, Oracle, SQL Server are the primary means used of storing, maintaining, and retrieving data. Microsoft developed the technology called ADO (ActiveX Data Objects) that provides generic access to data, including Access, Lotus Notes, Excel, Word, etc. A sample Access database will be downloaded for use with the following examples.

Exercise 1 - Using Access

 The steps to using the database are:

  1. Download the sample Access database to your machine, put on the W:\N342 directory with the download name so the examples below are simpler to follow.
  2. Access - Open Access, then the Comp-2000.mdb database. 
  3. Tables - Open the EMPLOYEE table as in the illustration at right. It contains employee first and last names, etc. 
  4. The Datasheet View in Access of the EMPLOYEE table appears below; the first row has John Smith for the first and last names respectively.

  5. Close the database, click .

 

Web Servers/Databases/ADO

Web applications that store persistent data implement a three-tier model consisting of:

  1. User interface on the browser.
  2. Logic on the Web server.
  3. Data storage on data server.

Tier 2 relates to ASP and server scripts, gathering and presenting data to the user, and storing or retrieving the data. To simplify database use, Microsoft has developed ActiveX Data Objects (ADO) for any application that supports ActiveX. 

The following JScript ASP program uses ADO to open the Comp-2000.mdb database, send the SQL statement to the database engine to return all records from the Employee table, and print the LNAME field of the first record, which happens to be Smith.

<%@ Language=JScript %>
<% 
  conn = Server.CreateObject("ADODB.Connection"); 
  conn.Open ("DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" + 
                     Server.MapPath("Comp-2000.mdb"));
  rs = conn.Execute("SELECT Fname, Lname FROM Employee");
  Response.Write(  

	"<TABLE BORDER=1>"+
	"   <TR>"+
	"       <TD>First</TD>"+
	"       <TD>Last</TD>"+
	"   </TR>"+
	"   <TR>"+
	"       <TD>" + rs("Fname") + "</TD>"+
	"       <TD>" + rs("Lname") + "</TD>"+
	"   </TR>"+
	"</TABLE>" 
   );
%>

Browser Output

First Last
John Smith

The key points of ADO illustrated are:

 

Iteration

Database tables generally consist of multiple records and iteration over the records allows each record to be accessed. The following example iterates over all employee records, generating a table of first and last names.
 

<%@ Language=JScript%>
<% 
  conn = Server.CreateObject("ADODB.Connection"); 
  conn.Open ("DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" + 
                     Server.MapPath("Comp-2000.mdb"));
  rs = conn.Execute("SELECT Fname, Lname FROM Employee");

  Response.Write(
	"<TABLE BORDER=1>"+
	"   <TR>"+
	"      <TD>First</TD>"+
	"      <TD>Last</TD>"+
	"   </TR>");
  
   while (!rs.EOF ) {  
	Response.Write(
	"   <TR>"+
	"            <TD>" + rs("Fname") + "</TD>"+
	"            <TD>" + rs("Lname") + "</TD>"+
	"   </TR>");  
         rs.MoveNext();
   }

   rs.Close();
   Response.Write( "</TABLE>" );
%>
Partial HTML listing

<TABLE BORDER=1>
  <TR>
     <TD>First</TD>
     <TD>Last</TD>
  </TR>
      <TR>
         <TD>John</TD>
         <TD>Smith</TD>
      </TR>
      <TR>
          <TD>Franklin</TD>
          <TD>Wong</TD>
      :
      :

Exercise  2 - ADO/SQL

Modify the above ASP script to list all employee first and last names and salary.

SQL Select

SELECT Fname, Lname FROM Employee

selects all Employee records but only the Fname and Lname fields.

SELECT Fname, Lname FROM Employee WHERE Lname > 'English'

selects only Employee records where the Lname field is greater than 'English'.

'English' is alphabetic so must be enclosed in quotes.

 

Exercise  3 - ADO/SQL

  1. Modify the Exercise 2 ASP script to list all employee first and last names and salary where salary is above 30000.
     
  2. Note that salary value is numeric so is not enclosed by single quotes in the SQL Select.

 

User Form Data

ASP scripts can interact with users using the same GET and POST methods previously examined. The following uses a form to collect user input, the last name of an employee, that is retrieved from the Employee table of our database source.

GET - With use of parameters to Request, the Web server parses the HTTP GET data and returns the values of the specified parameters. If your application requires unparsed data from the form, you can access it by calling Request without any parameters.

The GET form with Last data is returned to the script and its value can be accessed by: Request("Last") which has the value Smith given the input to the form in the example below. Note in the ASP that when Last is undefined, all records of the table are retrieved and displayed. For Last=Smith the SQL statement generated will be:

SELECT * FROM Employee WHERE LNAME = 'Smith'

Search.htm
<H1>Employee Search</H1>
<form method = "GET"
      action="Search.Asp">
   Employee Last Name 
  <INPUT TYPE = "text" 
              name="Last" size="20" />
</form>

Search Form

Results of Search

Search.Asp
<%@ Language=JavaScript%> 
<% conn = Server.CreateObject("ADODB.Connection"); 
      conn.Open ("DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" + 
                        Server.MapPath("Comp-2000.mdb"));

      if (Request("Last") == "") 
          rs = conn.Execute("SELECT * FROM Employee");
      else
          rs = conn.Execute("SELECT * FROM Employee WHERE Lname = '" + 
                                     Request("Last") + "'"); 

  Response.Write(
	"<TABLE BORDER=1>"+
	"   <TR>"+
	"      <TD BGCOLOR='silver'>First</TD>"+
	"      <TD BGCOLOR='silver'>Last</TD>"+
	"   </TR>");
  
   while (!rs.EOF ) {  
	Response.Write(
	"   <TR>"+
	"            <TD>" + rs("Fname") + "</TD>"+
	"            <TD>" + rs("Lname") + "</TD>"+
	"   </TR>");  
         rs.MoveNext();
   }

   rs.Close();
   Response.Write( "</TABLE>" );
%>

 

Exercise  4 - ADO/User Data

  1. Modify the above JavaScript Search.ASP script and Search.htm HTML to list all employee first and last names and salary where salary is greater than some value specified through the form.
     
  2. Use the Get method.
     
  3. Note that salary value is numeric so is not enclosed by single quotes in the SQL Select.
     
  4. Run the ASP two ways:
    1. using Search.htm page.
    2. entering the URL by hand; in the above example: Search.asp?Last=Smith

 

JavaScript and Exceptions

In the following note the use of try and catch which perform exception handling in Java and JavaScript. When ADO methods encounter an error, such as attempting to read more records than there are in the record set, the method throws an exception. When the method call is enclosed by the try operation, the exception is caught by the nearest catch. 
 

JavaScript Search.Asp

<%@ Language=JavaScript%> 

 <% 
    try {
     
conn = Server.CreateObject("ADODB.Connection");
     conn.Open ("DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" +
                        Server.MapPath("Comp-2000.mdb"));
   
     if (Request("Last") == "")                       // No data sent by browser
        rs = conn.Execute("SELECT * FROM Employee");
     else
        rs = conn.Execute("SELECT * FROM Employee WHERE Lname = '" + Request("Last") + "'"); 
  %>

  <TABLE BORDER=1> 
    <TR> 
        <TH BGCOLOR="silver">First</TH>
        <TH BGCOLOR="silver">Last</TH> 
    </TR> 

  <% while (!rs.EOF) {       %> 
         <TR>  
             <TD> <%= rs("Fname") %></TD> 
             <TD> <%= rs("Lname") %></TD> 
        </TR> 
  <% 
            rs.MoveNext(); 
     
      rs.Close();  
    }
    catch(e) { Response.Write("<br>Oops! Database Exception "+e); }
    %> 
  </TABLE>

 

Exercise  4.5 - Exceptions

  • To observe the effect of a run time error on a try/catch, modify the above JavaScript Search.ASP script to use the non-existent "Comp-2020.mdb".

 

SQL Update, Insert and Delete

SQL Select reads a database table, producing a set of records matching the selection criteria; Update, Insert, Delete and some other operations write or otherwise modify the table.

To modify databases or other files through ASP scripts, IIS must have write access to the files.

IIS - If you are administering a Web server

A common error message indicating security problems when using IIS on XP is: 

Operation must use an updateable query

The correction is to give the Internet Guest account IUSR_MACHINE Write permissions on the directory containing the .mdb file.

Do the following to correct while logged in as an administrator:

  1. Start | Settings | Control Panel | Administrative Tools | Computer Management | Local Users and Groups |
    Users | IUSR_MACHINE (i.e. the Internet Guest Account) | Right Click | Properties | Member Of | Administrators
  2. Sometimes you may have to delete the .mdb database file from the directory and copy back to the directory.
  3. Reboot machine.

 

Delete

The following example deletes an existing record from the Employee table only if a record with the SSN='666666666' is already in the table. 

JavaScript Delete.Asp
<%@ Language=JScript%>
<%	
  conn = Server.CreateObject("ADODB.Connection");
  conn.Mode = 3;
  conn.Open ("DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" + 
                     Server.MapPath("Comp-2000.mdb"));

  conn.Execute("DELETE from Employee where SSN='666666666'");

  conn.Close();
%>

Note the ADO is slightly more complicated, requiring to set the connection mode = 3 for write access.  The following example on insert provides a more complete perspective.

Exercise  5 - Delete

  1. Access - Open Access, then the Comp-2000.mdb database. 
     
  2. Tables - The database contains an EMPLOYEE table as in the illustration at right. It contains employee first and last names, etc. 
     
  3. Enter your name, SSN of 666666666.
     
  4. Copy and paste the above Delete.Asp script.
     
  5. With the Access EMPLOYEE table window visible, open the Delete.Asp script in the browser.
     
  6. You may need to close and open the EMPLOYEE table to see the effect.

 

Update

The following example updates the salary of a record from the Employee table only if a record with the SSN='123456789' is already in the table. The lucky employee is given a 10% raise each time the script executes.

JavaScript Update.Asp
<%@ Language=JScript%>
<%	
  conn = Server.CreateObject("ADODB.Connection");
  conn.Mode = 3;
  conn.Open ("DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" + 
                     Server.MapPath("Comp-2000.mdb"));

  conn.Execute("UPDATE Employee SET Salary = Salary * 1.10 where SSN= '123456789'  ");

  conn.Close();
%>

 

Exercise  6 - Update

  1. Copy and paste the Update.Asp script.
  2. Access - Open Access, then the Comp-2000.mdb database. 
  3. With the Access EMPLOYEE table window visible, open the Update.Asp script in the browser.
  4. You may need to close and open the EMPLOYEE table to see the effect.

 

Insert

The following example inserts a new record into the Employee table only if a record with the same SSN is not already in the table. Only four of the record fields are inserted: SSN, FNAME, LNAME, DNO.

Note that running the script once inserts the record and displays "Record Inserted", running a second time displays "Name already in table". The SSN is the primary table key, attempting to insert a record with the same primary key as one already in the table violates the integrity of the database and is an error. Testing if(rs.EOF) ensures that when true the record can be safely inserted.

Note that

returns the record set resulting from the SELECT.

JavaScript Insert.Asp
<%@ Language=JScript%>
<%	
  conn = Server.CreateObject("ADODB.Connection");
  conn.Mode = 3;
  conn.Open ("DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" + 
                     Server.MapPath("Comp-2000.mdb"));
  rs = conn.Execute("SELECT * FROM Employee where SSN='666666666'");

  if (rs.EOF) {

    conn.Execute("Insert into Employee (SSN, FNAME, LNAME, DNO) values ('666666666', 'Frank', 'Smith', '5')");

    Response.Write("Record Inserted");
  }
  else {
    Response.Write("Name already in table");
  }
  conn.Close();
%>

 

Exercise  7 - Insert

  1. Access - Open Access, then the Comp-2000.mdb database. 
  2. Copy and paste the Insert.Asp script.
  3. Modify to insert a record with your name and a Salary of $1,000,000; this is a numeric field, no quotes needed.
  4. With the Access EMPLOYEE table window visible, open the Insert.Asp script in the browser.
  5. You may need to close and open the EMPLOYEE table to see the effect.
  6. Run Insert.asp again, an error "Name already in table" should be reported.

 

Common ADO methods

Each ASP language (JavaScript, VBScript, PerlScript) varies somewhat on the syntax but each implements the same ADO methods.

  • ADO object creation.
    • JavaScript - rs = Server.CreateObject("ADODB.Recordset");
    • Perl - $rs = Win32::OLE->new('ADODB.Recordset');
    • VB - rs = Server.CreateObject("ADODB.Recordset")
  • Open database and execute SQL.
    • JavaScript - rs.Open ("SELECT * FROM Employee;", "Data Source=N342db;");
    • Perl -  rs->Open("SELECT * from Employee;","Data Source=N342db;")
    • VB - rs.Open "SELECT * FROM Employee" , "Data Source=N342db;" 
  • Move to the first record.
    • JavaScript - rs.MoveFirst();
    • Perl - rs->MoveFirst()
    • VB - rs.MoveFirst()
  • Move to next record.
    • JavaScript - rs.MoveNext();
    • Perl - rs->MoveNext()
    • VB - rs.MoveNext()
  • Test for end of file.
    • JavaScript - rs.EOF
    • Perl - rs->EOF
    • VB - rs.EOF
  • Test for beginning of file
    • JavaScript - rs.BOF
    • Perl - rs->BOF
    • VB - rs.BOF
  • Access current record fields
    • JavaScript - rs("Lname")
    • Perl - rs->Fields('LNAME')->value
    • VB - rs("Lname")
  • Close the recordset.
    • JavaScript - rs.Close();
    • Perl - rs->Close()
    • VB - rs.Close