Chapter 4
Relational Database Languages

This chapter describes relational database languages.  Sections 1  and
2  show  examples  of  how  the  languages  of  Chapter 2 (the fourth-
generation and the logic-based  languages)  apply  to  the  relational
databases.    The   principal  example  of  Section  1  discusses  the
principles  of  writing  a  transaction-processing  program   for   an
application.   The  optional Section 3 defines the Relational Algebra.
Section 4 describes SQL, a popular commercial language related to  the
Relational  Predicate Calculus of Section 2.  The expressive power and
equivalence of relational languages is discussed in Section 5.

4.1.   Fourth-generation Programming

The structured extension of Pascal for  relational  databases  is  the
same as the extension of Pascal for semantic databases but is used for
the relational schema.  (Every relational schema is a  binary  schema.
Thus,  every  language  used  for the Binary Model can be used for the
Relational Model.)

Example 4-1.

The university has decided to expel  all  the  students  whose
average  grade  is  below  60  (out  of 100).  To prevent this
wrong-doing  to  computer  science  students,  the  department
offered  a fictitious course, Computer-Pass, by Prof. Good, in
which  all  computer  science  students  are  to   receive   a
sufficient grade so as to not to be expelled, if possible.

The  following  program  fabricates  Prof.    Good   and   the
Computer-Pass  course, enrolls students in this course, grades
them accordingly, and  prints  the  names  of  those  computer
science students whom this measure cannot help.

program Pass (Input, Output, UNIVERSITY-DB, UNIVERSITY-MASTER-VIEW);

var Computer-Pass-Course, Prof-Good, Good-Offer, computer-science-
     name, comp-science, cs-student, her-enrollment, fictitious-
     enrollment: ABSTRACT;

     the-grade,  desired-grade,   number-of-grades,   total-of-grades,
     current-year:  INTEGER;

begin

(* Get the current year from the standard input file.*)

     read (current-year);

transaction begin

     (* Fabricate the course.*)

          create new Computer-Pass-Course in COURSE;

          Computer-Pass-Course. NAME-key :=  `Computer Pass';

     (* Fabricate the Prof. Good.*)

          create new Prof-Good in INSTRUCTOR;

          Prof-Good. LAST-NAME  :=  `Good';

          Prof-Good. ID-key  :=  1234; (*Let's hope that this
               fabricated ID number does not already belong to a
               legitimate instructor.  Otherwise, an error will
               result.*)

     (* Fabricate the offering.*)

          create new Good-Offer in COURSE-OFFERING;

          Good-Offer. COURSE-NAME-in-key  :=  `Computer Pass';

          Good-Offer. INSTRUCTOR-ID-in-key  :=  1234;

          Good-Offer. YEAR   :=  current-year;

          Good-Offer. SEASON   :=  `Winter'

     end;

(*The following two nested loops will be performed only once.  Inside
     the body of the second loop, the variable comp-science will refer
     to the Computer Science Department.*)

for computer-science-name in DEPARTMENT-NAMING

          satisfying (computer-science-name. NAME-key = `COMPUTER
               SCIENCE') do

     for comp-science in DEPARTMENT

               satisfying (comp-science. MAIN-NAME-key = comp-
                    science-name. MAIN-NAME) do begin

          (*Make believe that Prof. Good works in Computer Science.*)

               (* In terms of the binary schema, relate:  Prof-Good
                    WORKS-IN comp-science *)

                    transaction begin

                         create new work in WORK;

                         work. INSTRUCTOR-ID-in-key :=  1234;

                         work. DEPARTMENT-MAIN-NAME-in-key :=  comp-
                              science.MAIN-NAME-key

                         end;

          for cs-student in STUDENT

                    satisfying  (cs-student. MAJOR-DEPARTMENT-MAIN-
                         NAME
                          = comp-science. MAIN-NAME-key) do

               begin (*the current computer science student*)

               (* calculate this student's current statistics:
                    number-of-grades and total-of-grades *)

                    number-of-grades  :=  0;

                    total-of-grades  :=  0;

                    for her-enrollment in COURSE-ENROLLMENT satisfying
                         (her-enrollment. STUDENT-ID-in-key = cs-
                         student. ID-key and not her-enrollment
                         FINAL-GRADE null) do begin

                         the-grade := her-enrollment. FINAL-GRADE;

                         number-of-grades := number-of-grades + 1;

                         total-of-grades := total-of-grades + the-
                              grade

                         end;

               (* calculate the minimal desired grade in computer-pass

                    course, solving the equation

                    (total+x)/(number+1)=60 *)

                    desired-grade  :=  60 * (number-of-grades + 1) -
                         total-of-grades;

               if desired-grade > 100 then

                    (* the student cannot be helped.  Print a message
                         *)

                         writeln (`  The student ', cs-student. LAST-
                              NAME, `  cannot be helped.  Sorry!')

               else if desired-grade > 60  then

                    transaction begin

                         create new fictitious-enrollment in COURSE-
                              ENROLLMENT;

                         fictitious-enrollment. STUDENT-ID-in-key  :=
                              cs-student. ID-key;

                         fictitious-enrollment. COURSE-NAME-in-key  :=
                              `Computer Pass';

                         fictitious-enrollment. INSTRUCTOR-ID-in-key
                              := 1234;

                         fictitious-enrollment. YEAR  := 1990;

                         fictitious-enrollment. SEASON  := `Winter';

                         fictitious-enrollment. FINAL-GRADE  :=
                              desired-grade

                         end (*transaction*)

               end (*current student*)

          end (*computer science department *)

end.

4.1.1.   Transaction processing

Many application programs process a continuous  sequence  of  end-user
requests  for  transactions.   In each cycle, such a program accepts a
request from an end-user, translates it from the data-entry form  into
the terms of the database, determines the validity of the request, and
performs it.

Most relational DBMS are unable to automatically enforce the integrity
constraints,  particularly  referential  integrity.  In this case, the
busy-work of manual integrity validation  must  be  performed  by  the
application programs processing the user transactions.

Example 4-2.

The following program reads from the standard input  a  series
of  requests  for  enrolling  students  in  classes. For every
request,  the  program  checks  its  integrity   against   the
database.   If  the  request is integral, the program performs
the update.  Otherwise, an error message is printed.

It is assumed that the DBMS is unable to automatically enforce
the referential integrity.

program Enroll (Input, Output, University-database, University-
     master-userview);

var

     student-id, instructor-id, year: Integer;

     course-name, season: String;

     student, instructor, course, quarter, offering, enrollment:
          ABSTRACT;

     student-ok, instructor-ok, course-ok, quarter-ok, offering-ok,
          enrollment-ok: Boolean;

procedure Erroneous-transaction (explanation: String);

     (*This procedure is called

           o   from  Transaction-error-handler,  when  an   error   is
               detected by the DBMS

           o   from the program, when an  error  is  detected  by  the
               program. *)

     begin

     writeln (`The enrollment request listed in the following line
          could not be granted for the reason: ', explanation);

     writeln (student-id, instructor-id, course-name, year, season)

     end

procedure Transaction-error-handler (error-description: String);

     begin

     Erroneous-transaction (concatenate(`System error: ', error-
          description);

     end

begin

while not eof(Input) do

transaction begin

     (* Get a request for the next enrollment transaction *)

          readln (student-id, instructor-id, course-name, year,
               season)

     (* Check student ID *)

          student-ok := false;

          for student in STUDENT

               satisfying (student. ID-key = student-id)

               do student-ok := true;

          if not student-ok then

               Erroneous-transaction (`No student known by the
                    student-id submitted in the first field of the
                    enrollment request');

     (* Check instructor ID *)

          instructor-ok := false;

          for instructor in INSTRUCTOR

               satisfying (instructor. ID-key = instructor-id)

               do instructor-ok := true;

          if not instructor-ok then

               Erroneous-transaction (`No instructor known by the
                    instructor-id submitted in the second field of the
                    enrollment request');

     (* Check course name *)

          course-ok := false;

          for course in COURSE

               satisfying (course. NAME-key = course-name)

               do course-ok := true;

          if not course-ok then

               Erroneous-transaction (`No course known by the course-
                    name submitted in the third field of the
                    enrollment request');

     (* Check quarter *)

          quarter-ok := false;

          for quarter in QUARTER

               satisfying (quarter. YEAR-in-key = year and quarter.
                    SEASON-in-key = season)

               do quarter-ok := true;

          if not quarter-ok then

               Erroneous-transaction (`No quarter known by the year
                    and season submitted in the fourth and fifth
                    fields of the enrollment request');

     (* Check the offering *)

          offering-ok := false;

          for offering in COURSE-OFFERING

               satisfying (offering. INSTRUCTOR-ID-in-key =
                    instructor-id and offering. COURSE-NAME-in-key =
                    course-name and offering. YEAR-in-key = year and
                    offering. SEASON-in-key = season)

               do offering-ok := true;

          if instructor-ok and course-ok and quarter-ok and not
               offering-ok then

               Erroneous-transaction (`No offering known by the
                    instructor-id, course, year and season submitted
                    in the second through fifth fields of the
                    enrollment request');

     (* The following check of nonduplicate enrollment is not strictly
          necessary,  since  it  can be performed automatically by the

          DBMS, which knows to enforce the  uniqueness  of  the  keys.
          Thus,  the only practical reason for this test is to produce
          a better message than what would be produced by  the  system
          by default. *)

     (* Check that student is not already enrolled in the offering *)

          enrollment-ok := true;

          for enrollment in COURSE-ENROLLMENT

               satisfying (enrollment. STUDENT-ID-in-key = student-id
                    and enrollment. INSTRUCTOR-ID-in-key =
                    instructor-id and enrollment. COURSE-NAME-in-key =
                    course-name and enrollment. YEAR-in-key = year and
                    enrollment. SEASON-in-key = season)

               do enrollment-ok := false;

          if not enrollment-ok then

               Erroneous-transaction (`The requested enrollment of the
                    student already exists')

     if student-ok and instructor-ok and course-ok and quarter-ok and
          offering-ok and enrollment-ok

     then

          (* Insert the new enrollment *)

               begin

               create new enrollment in COURSE-ENROLLMENT;

               enrollment. STUDENT-ID-in-key := student-id;

               enrollment. INSTRUCTOR-ID-in-key := instructor-id;

               enrollment. COURSE-NAME-in-key := course-name;

               enrollment. YEAR-in-key := year;

               enrollment. SEASON-in-key := season

               end

     end (*transaction*)

end.

4.2.   Logic for Relational Databases

Relational Calculus - Predicate Calculus, when used for the relational
     schema.   (Since  every  relational schema is a binary schema, we
     already know Relational Calculus.)

Example 4-3.

What are the last names of all the students?

get s. LAST-NAME

     where s is a STUDENT

Example 4-4.

What are the distinct last names of the  students?   (No  name
may be printed twice.)

get n

     where

          exists s in STUDENT:

               n = s. LAST-NAME

Tuple-oriented Relational Calculus - Relational calculus with the
     following restriction: the quantification is done only on
     abstract categories (i.e., tables).

     Among the languages of the Relational Model, more  languages  are
     based  on  the tuple-oriented Predicate Calculus than on the more
     general form of Predicate Calculus.

Example 4-5.

The previous  example  was  not  in  the  tuple-oriented  form
because  the  variable  n  was  implicitly quantified over the
concrete category String.

The following examples are in tuple-oriented form.

Example 4-6.

Has every student enrolled in at least one course in 1990?

     for every st in STUDENT:

          exists enrl in COURSE-ENROLLMENT:

               ((enrl. STUDENT-ID-in-key = st.ID-key ) and
                    (enrl. YEAR=1990))

Example 4-7.

Who took Prof. Smith's courses?

get student.LAST-NAME where

     (student is a STUDENT and

     exists enrl in COURSE-ENROLLMENT:

          (enrl. STUDENT-ID-in-key=student.ID-key and

          exists inst in INSTRUCTOR:

               (inst.LAST-NAME = `Smith' and

               enrl. INSTRUCTOR-ID-in-key=inst.ID-key)))

Example 4-8.

Print the average grade of every computer science student.

     get student. LAST-NAME,

          (average enrollment. FINAL-GRADE

                    where

                         enrollment. STUDENT-ID-in-key =
                              student. ID-key)

     where

          student is a STUDENT and

          (student. MAJOR-DEPT-MAIN-NAME = `Computer Science')

Example 4-9.

How many students are there in the university?

     get (count std where std is a STUDENT)

Example 4-10.

What students have their average grade below 60?

     get std. LAST-NAME

     where std is a STUDENT and

          60 >

               average enrl. FINAL-GRADE

                    where

                         enrl is a COURSE-ENROLLMENT and

                         enrl.STUDENT-ID-in-key = std.ID-key

4.3.   *Relational Algebra

Relational Algebra is an algebraic language in which  new  tables  are
defined by applying operators to other tables.

This is a language of expressions.  In it, a new table is  defined  as
an expression involving original tables and operators.

The most important operators are:

 o   Projection operator creates a new table containing  some  of  the
     columns of another table.

 o   Join operator combines the rows of the first table with "related"
     rows of the second table.

 o   Selection operator extracts some rows from a table according to a
     given condition on the values of the row.

Example 4-11.

{The last names of the students born in 1975} =

(project-the-column-LAST-NAME

     (select-the-rows-where-the-BIRTH-YEAR-is-1975

          (the table STUDENT)))

In this section, the operators of Relational Algebra  are  defined  by
inference laws in Predicate Calculus.

Consider two tables:

     table T, whose attributes are A ,...,A
                                    1      n

     table T', whose attributes  are A' ,...,A'
                                       1       n'

1.   The projection operator (. . .[attributes]) creates a  new  table
     containing some of the columns of another table.

     Let F ,..., F  be some of the attributes (columns)  of  table  T.
          1       k
     Then

     T [F ,..., F ] =
         1       k

          get F : v ,..., F : v
               1   1       k   k

               where exists x in T:

                    x.F =v  and ... and x.F =v
                       1  1                k  k

     Note:  When several tuples of T  have  the  same  values  in  the
          columns  being  projected,  only  one row will appear in the
          result.  Thus, the resulting table  may  have  fewer  tuples
          than T.

Example 4-12.

A list of the distinct last names of the students =

     STUDENT[LAST-NAME]=

     get LAST-NAME: name

          where

               exists x in STUDENT:

                    x. LAST-NAME = name

Example 4-13.

Last names and majors of all the students =

     STUDENT[LAST-NAME, MAJOR-DEPARTMENT-MAIN-NAME] =

     get LAST-NAME: name, MAJOR-DEPARTMENT-MAIN-NAME : major

          where

               exists x in STUDENT:

                    x. LAST-NAME = name and

                    x. MAJOR-DEPARTMENT-MAIN-NAME = major

Example 4-14.

We can define an inferred table STUDENT-BASIC  containing  all
the information from the table STUDENT except the departments:

     STUDENT-BASIC = STUDENT [ID-key, LAST-NAME, FIRST-NAME,
          BIRTH-YEAR, ADDRESS]

2.   The renaming operator (.  .  .[attribute/new-name])  changes  the
     name of a column in a table.

     T[A  / A ] =
        i    i

          (*Copy the attributes A ,...,A   ,A   ,...,A ; rename the
                                 1      i-1  i+1      n
 .*)           attribute A
i
          get A : x.A ,...,  A   : x.A   ,  A : x.A ,  A   :
               1     1        i-1     i-1    i     i    i+1
               x.A   ,...,  A : x.A
                  i+1        n     n

               where x is a T

Example 4-15.

A table just like STUDENT,  with  `FAMILY-NAME'  column  title
instead of `LAST-NAME':

               STUDENT [LAST-NAME/FAMILY-NAME]

3.   The cartesian product operator x

     For every row of the first operand  and  for  every  row  of  the
     second  operand,  the product operator produces the concatenation
     of the two rows.

     The number of rows in the result =

          (the number of rows in the first operand x

          the number of rows in the second operand)

     The number of columns in the result =

          (the number of columns in the first operand +

          the number of columns in the second operand)

     This operation is syntactically erroneous  when  the  two  tables
     have a common attribute.

     Cartesian product =

     TxT' =

          get A :x.A ,...,  A :x.A ,  A' :y.A' ,...,  A  :y.A
               1    1        n    n     1     1        n'    n'

               where x is a T and y is a T'

4.   Set operators

     The following operators are defined only when the two tables have
     the same attributes.

     a.   Union of tables produces all the rows of the first table and
          all the rows of the second table.

          TUT' =

               get A :v ,..., A :v
                    1  1       n  n

                    where

                         exists x in T:

                              x.A =v  and ... and x.A =v
                                 1  1                n  n

                         or exists x in T':

 =v  and ... and x.A =v       x.A
1  1                n  n

Example 4-16.

All the persons =

     STUDENT-BASIC U INSTRUCTOR =

          get ID-key : id,..., ADDRESS : addr

               where

                    exists x in STUDENT-BASIC:

                         x.ID-key = id and ... and x.ADDRESS =
                              addr

                    or exists x in INSTRUCTOR:

                         x.ID-key = id and ... and x.ADDRESS =
                              addr

     b.   Intersection of tables produces the  rows  which  appear  in
          both tables.

          TT' =

 :v ,..., A :v get A
1  1       n  n

                    where

                         exists x in T:

                              x.A =v  and ... and x.A =v
                                 1  1                n  n

                         and exists x in T':

                              x.A =v  and ... and x.A =v
                                 1  1                n  n

Example 4-17.

Instructors who are students =

     INSTRUCTOR  STUDENT-BASIC

     c.   The difference of tables operator (-) produces the  rows  of
          the first table which do not appear in the second table.

          T-T' =

               get A :v ,..., A :v
                    1  1       n  n

                    where

                         exists x in T:

                              x.A =v  and ... and x.A =v
                                 1  1                n  n

                         and not exists x in T':

                              x.A =v  and ... and x.A =v
                                 1  1                n  n

Example 4-18.

Instructors who are not students =

     INSTRUCTOR - STUDENT-BASIC

5.   The selection operator (...[condition]) extracts some rows from a
     table according to a given condition for the values of the row.

     Let F ,..., F  be some of the attributes of T.
          1       k

     Let boolexp(v ,...,v   be a Boolean expression with k variables.
                  1      k)

     Then

     T [boolexp(F ,..., F )] =
                 1       k

          get x.A ,..., x.A
                 1         n

               where

                    x is a T and

                         boolexp(x.F ,..., x.F )
                                    1         k

Example 4-19.

The student whose first name is Mary =

     STUDENT [FIRST-NAME=`Mary']

Example 4-20.

The instructor whose name is Chung and who is  not  a  student
(as distinguished from another Chung who is both an instructor
and a student.)

All the instructors whose name is `Chung' =

     INSTRUCTOR [LAST-NAME=`Chung']

The nonstudent instructor(s) whose name is `Chung' =

     INSTRUCTOR [LAST-NAME=`Chung'] - STUDENT-BASIC

Example 4-21.

Names of the instructors teaching databases.

     All  the  combinations  of  instructors   and   offerings
          (including the unrelated ones) =

          (INSTRUCTOR x COURSE-OFFERING)
                                          (*product*)

     All combinations of instructors and their offerings =

          (INSTRUCTOR x COURSE-OFFERING)
               [ID-key=INSTRUCTOR-ID-in-key]
                                        (*selection*)

     All combinations of instructors and their offerings of
          Databases =

          (INSTRUCTOR x COURSE-OFFERING)
               [ID-key=INSTRUCTOR-ID-in-key]
               [COURSE-NAME-in-key=`Databases']
                                        (*selection*)

     The last names of the instructors offering Databases =

          (INSTRUCTOR x COURSE-OFFERING)
               [ID-key=INSTRUCTOR-ID-in-key]
               [COURSE-NAME-in-key=`Databases']
               [LAST-NAME]
                                       (*projection*)

6.   The join operator combines the  rows  of  the  first  table  with
     "related"  rows  of  the  second  table.   It  is equivalent to a
     selection from the cartesian product.

     T[boolexp(attributes)]T' =

          (TxT')[boolexp(attributes)]

Example 4-22.

Names of instructors teaching databases.

     All combinations of instructors and their offerings =

          (INSTRUCTOR [ID-key=INSTRUCTOR-ID-in-key] COURSE-
               OFFERING)
                                             (*join*)

     The last names of the instructors offering databases =

          (INSTRUCTOR [ID-key=INSTRUCTOR-ID-in-key] COURSE-
               OFFERING)
               [COURSE-NAME-in-key=`Databases']
               [LAST-NAME]

7.   The natural join operator [] combines two tables according to the
     equal  values  of the common attributes (column names) of the two
     tables.

     Let the table T have k attributes with  names  identical  to  the
     names of k attributes of the table T', that is:

      o   the attributes of T are: A ,...,A , A   ,...,A
                                    1      k   k+1      n

      o   the attributes of T' are: A ,...,A , A'   ,...,A'
                                     1      k    k+1       n'

     Then

          T[]T' =

               get A :v ,..., A :v , A'   :w   ,..., A'  :w
                    1  1       n  n    k+1  k+1        n'  n'

                    where

                         exists x in T:

                              x.A =v  and ... and x.A =v
                                 1  1                n  n

                         and exists x in T':

                              x.A =v  and ... and x.A =v  and
                                 1  1                k  k
                                   x.A'   =v    and ... and x.A'  =w
                                       k+1  k+1                 n'  n'

Example 4-23.

Names of instructors teaching databases.

The table INSTRUCTOR with the column ID-key renamed  in  order
to be naturally joinable with the table COURSE-OFFERING =

     (INSTRUCTOR [ID-key/INSTRUCTOR-ID-in-key]
                                                   (*rename*)

All combinations of instructors and their offerings =

     (INSTRUCTOR [ID-key/INSTRUCTOR-ID-in-key] []
          COURSE-OFFERING)
                                             (*natural join*)

The last names of the instructors offering databases =

     (INSTRUCTOR [ID-key/INSTRUCTOR-ID-in-key] []
          COURSE-OFFERING)
          [COURSE-NAME-in-key=`Databases']
          [LAST-NAME]

Uses of the Relational Algebra:

1.   Specification of userviews (inference rules).

2.   Specification of queries.  Albeit, the language is  not  friendly
     enough to be used for specification of complex queries.

3.   An  intermediate  language,  because  it  is  easy  to  implement
     Relational  Algebra.   Other,   more  friendly  languages, can be
     translated into Relational Algebra.

4.   A tool to evaluate  and  compare  different  languages.   We  can

     estimate  the  expressive  power  of  an  arbitrary  language  by
     checking whether it is

     a.   Able  to  specify  every  query  expressible  in  Relational
          Algebra.

     b.   Able  to  specify  every  query  expressible  in  Relational
          Algebra and more.

     c.   Able to specify a  subset  of  the  queries  expressible  in
          Relational Algebra, where the subset is defined by weakening
          the Algebra through eliminating some of its operators.   The
          list  of  the eliminated operators shows the weakness of the
          language.  The list of the  remaining  operators  shows  the
          power of the language:

           o   Many simple query languages can express projection  and
               selection but not join or difference.

           o   More powerful languages can express join.

           o   Languages which are even more powerful can also express
               difference.

4.4.   SQL

4.4.1.   Preview

SQL has become  a  very  popular  language  of  commercial  relational
database management systems.

The acronym SQL stands for Structured Query Language.

A basic query in SQLselects the values of some attributes

                    from some rows of a table or tables

                    where the rows satisfy a condition

Example 4-24.

When was student Russel born?

     select BIRTH-YEAR

     from STUDENT

     where LAST-NAME=`Russel'

Example 4-25.

List the names of all students.

     select FIRST-NAME, LAST-NAME

     from STUDENT

     where true

Example 4-26.

What courses has Prof. Graham taught?

     select COURSE-NAME

     from COURSE-OFFERING, INSTRUCTOR

     where INSTRUCTOR. NAME = `Graham'  and INSTRUCTOR. ID =
          COURSE-OFFERING.  INSTRUCTOR-ID

4.4.2.   Basic queries

Syntax:

     select expression ,..., expression
                      1                n

     from table  var ,..., table  var
               1    1           n    n

     where condition

The condition is a Boolean expression  without  quantifiers.   It  may
depend on the variables var ,...,var .
                           1        n

Meaning:

     get expression ,..., expression
                   1                n

     where

          var  is a table  and ... var  is a table  and
             1           1            n           n

          condition

Example 4-27.

Print the names of the pairs of students who live together.

     select  s .LAST-NAME, s .LAST-NAME
              1 ---- ----   2 ---- ----

     from  STUDENT s , STUDENT s
           -------  1  -------  2

     where  s .ADDRESS = s .ADDRESS
             1 -------    2 -------

Abbreviation:

     If a table T  appears exactly once in the from list, then it does
                 i                             ----
     not have to be explicitly accompanied by a variable.  Implicitly,
     the name of the variable is identical to the name of the table.

          select expression ,..., expression
                           1                n

          from table  ,..., table
                    1            n

          where condition

Example 4-28.

Print the names of the pairs of a student  and  an  instructor
who live together.  (This includes an instructor who is also a
student and lives with alone.)

     select  STUDENT.LAST-NAME, INSTRUCTOR.LAST-NAME

     from  STUDENT, INSTRUCTOR

     where  STUDENT.ADDRESS = INSTRUCTOR.ADDRESS

          Abbreviation:  When there is only  one  table  in  the  from
               list,  then  whenever T.attribute appears in the query,
               it may be shortened to attribute without the prefix T.

Example 4-29.

Print the names and the  addresses  of  all  computer  science
students.

     select  LAST-NAME, ADDRESS

     from  STUDENT

     where  MAJOR-DEPARTMENT-MAIN-NAME = `Computer Science'

          Abbreviation:  When the select  list  consists  of  all  the
               attributes  of  the from tables, the select list may be
               abbreviated by "select +".

Example 4-30.

Print the names (last and first), the  IDs,  the  birth-years,
the  major  and  minor  departments,  and the addresses of all
computer science students.

     select  +

     from  STUDENT

     where  MAJOR-DEPARTMENT-MAIN-NAME = `Computer Science'

          Note:

                o   The output of a query is a  partial  instantaneous
                    binary database.  It can be printed as a table (in
                    the common sense of the word table).

                o   Often, but not always, the output of a query is an
                    instantaneous table in the sense of the Relational
                    Model.  This is not always true since  the  output
                    of  a  query  may  contain identical rows, while a
                    relational instantaneous  table  may  not  contain
                    identical rows.

4.4.3.   Basic aggregates

Basic aggregates are predefined functions which  are  applied  to  the
whole  output of a query.  Syntactically, the functions are applied to
the expression(s)  in the select list.

1.   count -- when this function is applied to  the  select  list,  it
     replaces  the  output  of  the query by the number of rows in the
     output.

Example 4-31.

How many computer science students are there?

     select count(+)

     from  STUDENT

     where  MAJOR-DEPARTMENT-MAIN-NAME = `Computer Science'

2.   avg -- when the select list consists of only one expression,  and
     the  expression  produces  numerical  values,  the  function  avg
     replaces the output by the average of the values in the output.

Example 4-32.

What is the average grade in the Databases course?

     select avg(FINAL-GRADE)

     from  COURSE-ENROLLMENT

     where  COURSE-NAME-IN-KEY = `Databases'

3.   sum -- when the select list consists of only one expression,  and
     the  expression  produces  numerical  values,  the  function  sum
     replaces the output by the sum of the values in the output.

4.   max -- when the select list consists of only one expression,  and
     the  expression  produces  numerical  values,  the  function  max
     replaces the output by the maximum of the values in the output.

5.   min -- when the select list consists of only one expression,  and
     the  expression  produces  numerical  values,  the  function  min
     replaces the output by the minimum of the values in the output.

6.   distinct --  eliminates  duplicate  rows  in  the  output.   This
     function  must  be  applied  to  the  whole select list. (In many
     implementations, this function is called "unique.")

Example 4-33.

List the distinct addresses of the students. (Do not list  the
same address twice.)

     select distinct(ADDRESS)

     from  STUDENT

     where  TRUE

7.   The function distinct can be combined with  any  other  aggregate
     function.   The  function  distinct  is  applied  first, and then
     another function is applied to the result.

Example 4-34.

How many departments have minor students?

     select  count (distinct MINOR-DEPARTMENT-MAIN-NAME)

     from  STUDENT

     where  TRUE

4.4.4.   Nested queries

Query forms are represented in SQL by  allowing  some  expressions  to
contain   variables  which  are  not  defined  (either  explicitly  or
implicitly) in the from list.  A query form would become  a  query  if
the  expressions  with undefined variables were replaced by constants.
Query forms are used in SQL primarily in  order  to  construct  nested
queries.

Example 4-35.

The following is not a query because it contains an  undefined
variable  s. It is a query form, which would become a query if
the expression s.ID-KEY were replaced by a constant,  such  as
345466.

     select +

     from COURSE-ENROLLMENT

     where s.ID-KEY = COURSE-ENROLLMENT.STUDENT-ID-IN-KEY

The nested queries are obtained in SQL by extending the syntax of  the
where  condition  by  allowing  the following subconditions within the
condition:

1.   exists    query-form

     This subcondition gives TRUE when the result of the query form is
     not empty - when it contains at least one row. (This subcondition
     is evaluated when all the  variables  on  which  the  query  form
     depends are interpreted.)

Example 4-36.

Find the names of the students who never took a course.

     select LAST-NAME

     from STUDENT

     where

          not exists

               (select +

               from COURSE-ENROLLMENT

               where STUDENT.ID-KEY = COURSE-
                    ENROLLMENT.STUDENT-ID-IN-KEY)

Example 4-37.

List the  instructor  IDs  and  course  names  such  that  the
instructor  is  the  exclusive teacher of the course (i.e.  no
other instructors have offered the course).

     select INSTRUCTOR-ID-in-key, COURSE-NAME-in-key

     from  COURSE-OFFERING co

     where not exists

          select INSTRUCTOR-ID-in-key

          from  COURSE-OFFERING co1

          where  co.COURSE-NAME-in-key=co1.COURSE-NAME-in-key
               and not co.INSTRUCTOR-ID-in-
               key=co1.INSTRUCTOR-ID-in-key

2.   expression    in    query-form-producing-only-one-value-per-row

     This  subcondition   gives TRUE when the value of the  expression
     constitutes a row in the output of the query-form

Example 4-38.

Find the names of the students who took at least one course.

     select LAST-NAME

     from STUDENT

     where

          (ID-KEY in

               select STUDENT-ID-IN-KEY

               from COURSE-ENROLLMENT

               where TRUE)

3.   expression    not in     query-form-producing-only-one-value-per-
     row

     This subcondition   gives TRUE when the value of  the  expression
     does not constitute a row in the output of the query-form

Example 4-39.

Find the names of the students who never took a course.

     select LAST-NAME

     from STUDENT

     where

          (ID-KEY not in

               select STUDENT-ID-IN-KEY

               from COURSE-ENROLLMENT

               where TRUE)

4.       in    query-form

     This subcondition   gives TRUE when the values of the expressions
     constitute a row in the output of the query-form

Example 4-40.

Find  the  names  of  the  students  who  may  be  spouses  of
instructors - those who have the same last name and address as
an instructor.

     select LAST-NAME, FIRST-NAME

     from STUDENT

     where

           in

               select LAST-NAME, ADDRESS

               from INSTRUCTOR

               where TRUE

5.       not in    query-form

     This subcondition   gives TRUE when the values of the expressions
     do not constitute a row in the output of the query-form

Example 4-41.

Find the names of some students who are certainly not  spouses
of instructors.

     select LAST-NAME, FIRST-NAME

     from STUDENT

     where

           not in

               select LAST-NAME, ADDRESS

               from INSTRUCTOR

               where TRUE

6.   query-form   contains   query-form

     This subcondition gives TRUE when every row produced by the right
     query form is also produced by the left query form.

Example 4-42.

Find the names of the students who took all the courses.

     select LAST-NAME, FIRST-NAME

     from STUDENT

     where

               select  COURSE-NAME-IN-KEY

               from COURSE-ENROLLMENT

               where STUDENT.ID-KEY = COURSE-
                    ENROLLMENT.STUDENT-ID-IN-KEY

          contains

               select NAME-KEY

               from COURSE

               where TRUE

7.   expression    comparison    query-form-producing-only-one-value

     The allowed comparisons are: =, <, >, >=, <=, <>.

Example 4-43.

Find the names of the students who took more than 1000  course
offerings.

     select LAST-NAME, FIRST-NAME

     from STUDENT

     where

          1000 <

               select count (+)

               from COURSE-ENROLLMENT

               where STUDENT.ID-KEY = COURSE-
                    ENROLLMENT.STUDENT-ID-IN-KEY

8.   expression    comparison     any   query-form

     This subcondition is TRUE if the comparison with at least one row
     of the query-form's output is TRUE.

Example 4-44.

Find the names of the students who studied  something  in  the
first 20 calendar years of their life.

     select LAST-NAME, FIRST-NAME

     from STUDENT

     where

          BIRTH-YEAR + 20 > any

               select YEAR

               from COURSE-ENROLLMENT

               where STUDENT.ID-KEY = COURSE-
                    ENROLLMENT.STUDENT-ID-IN-KEY

9.   expression    comparison     all   query-form

     This subcondition is TRUE if the comparison with every one of the
     query-form's output rows is TRUE.

Example 4-45.

Find the names of the students who studied nothing (as far  as
the  database  knows)  in the first 20 calendar years of their
life.

     select LAST-NAME, FIRST-NAME

     from STUDENT

     where

          BIRTH-YEAR + 20 <= all

               select YEAR

               from COURSE-ENROLLMENT

               where STUDENT.ID-KEY = COURSE-

                    ENROLLMENT.STUDENT-ID-IN-KEY

Example 4-46.

List the  instructor  IDs  and  course  names  such  that  the
instructor  is  the  exclusive teacher of the course (i.e.  no
other instructors have offered the course).

     select INSTRUCTOR-ID-in-key, COURSE-NAME-in-key

     from  COURSE-OFFERING  co

     where INSTRUCTOR-ID-in-key =  all

          select INSTRUCTOR-ID-in-key

          from  COURSE-OFFERING  co1

          where  co.COURSE-NAME-in-key=co1.COURSE-NAME-in-key

Example 4-47.

An alternative code for the above query:

     select INSTRUCTOR-ID-in-key, COURSE-NAME-in-key

     from  COURSE-OFFERING  co

     where 1 =

          select count (distinct INSTRUCTOR-ID-in-key)

          from  COURSE-OFFERING  co1

          where  co.COURSE-NAME-in-key=co1.COURSE-NAME-in-key

4.4.5.   Grouping of rows

The aggregate functions can by applied to subsets of rows produced  by
select.   For  this  purpose,  the  rows  resulting from select can be
partitioned into groups according to the values of some attributes.

Syntax:

          select expression ,..., expression
                           1                n

          from table  var ,..., table  var
                    1    1           n    n

          where condition

          group by attribute ,..., attribute
                            1               k

     Each attribute  has the form
                   i

                          variable.attribute-name

     When no ambiguity arises, the table-name can be used  instead  of
     the variable:

                         table-name.attribute-name

     When no ambiguity further arises, the table-name can be omitted:

                              attribute-name

Meaning:

     The rows satisfying the condition are  combined  into  groups  so
     that  in  each group the attributes of the grouping have constant
  andvalues; thathis,atwogrows rf  and
1      2
     only if

                   r .attribute  = r .attribute  and
                    1          1    2          1
                   r .attribute  = r .attribute  and ...
                    1          2    2          2
                   r .attribute  = r .attribute
                    1          k    2          k

     For every group, only one  cumulative  row  is  produced  in  the
     result.   The  resulting cumulative row is obtained by evaluation
     of the expressions of the select clause.  The aggregates in those
     expressions  are  interpreted as applying not to the whole output
     but only to the rows comprising one group.

Example 4-48.

For every  department,  list  the  number  of  instructors  it
employs.

     select  DEPARTMENT-MAIN-NAME-in-key, count(INSTRUCTOR-

          ID-in-key)

     from  WORK

     group by  DEPARTMENT-MAIN-NAME-in-key

Example 4-49.

For every student who took classes  in  a  summer,  for  every
instructor  who  gave grades to the student in a summer, print
the average of the summer grades given by  the  instructor  to
the student.

     select STUDENT-ID-in-key, INSTRUCTOR-ID-in-key,
          avg(FINAL-GRADE)

     from  COURSE-ENROLLMENT

     where   SEASON = `Summer'

     group by    STUDENT-ID-in-key, INSTRUCTOR-ID-in-key

Some of the groups produced by group by can be screened out  according
to  the  values  of aggregate functions applied to the group.  A group
screening condition can be specified in a having clause as follows.

     select  expressions

     from  tables

     where  condition-on-the-source-rows-of-the-tables

     group by  attributes

     having  condition-on-the-groups

The condition-on-the-groups is a Boolean  expression.   The  aggregate
functions appearing in this condition apply to the rows comprising one
group.

Example 4-50.

What departments employ more than 100 instructors each?

     select  DEPARTMENT-MAIN-NAME-in-key

     from  WORK

     where  true

     group by  DEPARTMENT-MAIN-NAME-in-key

     having count(distinct INSTRUCTOR-ID-in-key) > 100

Example 4-51.

For every student who took classes  in  a  summer,  for  every
instructor who gave grades to the student in a summer, so that
the average of the summer grades given by  the  instructor  to
the  student  is  greater  than  60,  print the average of the
summer grades given by the instructor to the student.

     select STUDENT-ID-in-key, INSTRUCTOR-ID-in-key,
          avg(FINAL-GRADE)

     from  COURSE-ENROLLMENT

     where   SEASON = `Summer'

     group by   STUDENT-ID-in-key, INSTRUCTOR-ID-in-key

     having    avg(FINAL-GRADE)  > 60

Example 4-52.

What students have taken classes with every instructor?

     select STUDENT-ID-in-key

     from  COURSE-ENROLLMENT

     group by   STUDENT-ID-in-key

     having    count(+)  =

          (select count(+)  from INSTRUCTOR)

4.4.6.   Sorting

The output of an SQL query can be sorted for the purpose  of  printing
in  any  desired  order or for delivery to an application program in a
desired order.  This is accomplished by an order by clause  specifying
one or more attributes to sort by:

     query

     order by attributes

When more than one sorting attribute is given,  the  output's  primary
order  is  according  to  the  first  attribute, then according to the
second, and so on.

Example 4-53.

List all computer science majoring students  sorted  by  their
minors.

     select +

     from  STUDENT

     where  MAJOR-DEPARTMENT-MAIN-NAME = `Computer Science'

     order by  MINOR-DEPARTMENT-MAIN-NAME

4.4.7.   Update transactions

Update transactions can be specified in SQL.

1.   Deleting a set of rows from a table.

          delete from table

          where  condition-on-rows-to-be-deleted

Example 4-54.

Delete the student whose ID is 11111.

     delete from   STUDENT

     where   ID-key = 11111

Example 4-55.

Delete all music majors.

     delete from   STUDENT

     where   MAJOR-DEPARTMENT-MAIN-NAME = `Music'

2.   Inserting a row into a table.

          insert into table
                              attribute ,...,attribute
                                       1              n

          values
                                  value ,...,value
                                       1          n

     The attributes of the table which are not specified in the insert
     command are set to null values for the row being inserted.

Example 4-56.

Let the instructor whose ID is 22222 work  in  the  department
whose main name is Arts.

     insert into   WORK

         INSTRUCTOR-ID-in-key, DEPARTMENT-MAIN-NAME-in-key

     values

                           22222, `Arts'

3.   Inserting a set of rows into  a  table.  A  set  of  rows  to  be
     inserted can be defined as the result of a query.

          insert into table
                              attribute ,...,attribute
                                       1              n

          query

Example 4-57.

Let all physics instructors work also in Arts.

     insert into   WORK

        INSTRUCTOR-ID-in-key, DEPARTMENT-MAIN-NAME-in-key

          select  INSTRUCTOR-ID-in-key, `Arts'

          from  WORK

          where   DEPARTMENT-MAIN-NAME-in-key = `Physics'

4.   Modifying the values of some attributes in a set  of  rows  of  a
     table.   The  set  of rows can be specified by a where condition.
     The new values can be specified as constants  or  as  expressions
     using the old values of the row being updated.

          update   table

          set
                 attribute =expression ,..., attribute =expression
                          1           1               n           n

          where   condition

Example 4-58.

Decrease by 10 percent all grades above 90.

     update   COURSE-ENROLLMENT

          set   FINAL-GRADE = FINAL-GRADE*0.9

          where   FINAL-GRADE > 90

4.4.8.   DDL

SQL has a data definition capability.

Specification of a table

     create table table-name

     attribute   data-type ,..., attribute   data-type
              1           1               n           n

Example 4-59.

create table QUARTER

YEAR-in-key         Integer

SEASON-in-key       String

Specification of a userview table

     create view new-table-name

 ,...attributete
1               n

     as select-command

Example 4-60.

create view TAUGHT

STUDENT-ID    HIS-TEACHER-ID

as

     select  STUDENT-ID-in-key, INSTRUCTOR-ID-in-key

     from  COURSE-ENROLLMENT

4.4.9.   SQL extension of Pascal

SQL can be used not only interactively but also as a DML extension  of
a  programming language. This section shows how SQL can be embedded in
Pascal.  The embedding in other programming languages is similar.

Host variables in SQL statements

     Wherever a constant can appear in SQL, a  host  program  variable
     can  appear  instead.  Before the SQL statement is performed, the
     variable is evaluated to give a value.   To  distinguish  between
     host  program variables and SQL variables, the host variables are
     preceded by a colon (:).

Example 4-61.

Create a new course whose  name  is  in  the  Pascal  variable
course-name.

insert into   COURSE

                           NAME-key

values :course-name

Example 4-62.

For each standard input line create a new course whose name is
the string appearing in that line.

var course-name: String;

begin

while not eof(Input) do begin

     readln (course-name);

     insert into   COURSE

          NAME-key values :course-name

     end

end.

Retrieving a row of values from the database

     If we anticipate that a select command will retrieve exactly  one
     row  of  data, we can have this data placed into variables of the
     host program by the following command.

                    select-command into host-variables

Example 4-63.

(* Get the  total  number  students  born  in  1980  into  the
variable myvar.*)

     select  count (+)

     from  STUDENT

     where BIRTH-YEAR = 1980

     into :myvar

Processing of multirow output of a query

     The program can retrieve a set of rows of data from the database.

      o   Such a set of rows can be defined as the output of a  select
          command.  The program would then process the retrieved rows,
          one row at a time.

Example 4-64.

select  BIRTH-YEAR

from  STUDENT

where   MAJOR-DEPARTMENT-MAIN-NAME  = `Management';

      o   To scan such rows in a program,  SQL  defines  a  cursor,  a
          logical  pointer  to  the current row.  The declaration of a
          cursor defines a query.

Example 4-65.

declare current-student cursor for
          select  BIRTH-YEAR

          from  STUDENT

          where   MAJOR-DEPARTMENT-MAIN-NAME  = `Management';

      o   The opening of the cursor performs the query.

Example 4-66.

open current-student;

      o   The fetch command then brings to the program  one  row  each
          time and advances the cursor to point to the next row.

Example 4-67.

fetch current-student into :birth-year;

      o   When a fetch is attempted beyond the last row in the  output
          of  a  query,  the  special variable sqlstatus is set to the
          value of the special constant not-found.

Example 4-68.

(* Print the logarithm of the birth year of  every  management
student (major) *)

     declare current-student cursor for

               select  BIRTH-YEAR

               from  STUDENT

               where   MAJOR-DEPARTMENT-MAIN-NAME  =
                    `Management';

     open current-student;

     repeat

          fetch current-student into :birth-year;

          if sqlstatus = not-found then writeln(log(birth-
               year))

     until sqlstatus = not-found

     The relevant commands are:

     a.   declare cursor-name  cursor for select-command

     b.   open cursor-name

     c.   fetch cursor-name into host-variables

Update and delete of fetched rows

     After a row has been  fetched,  it  can  be  updated  or  deleted
     provided the row belongs to one table of the schema (and not to a
     join of tables).

     a.   update table-name

          set
              attribute =expression  ,..., attribute =expression
                       1           1                n           n
          where current of cursor-name

Example 4-69.

(* Replace the birth year of every management student  (major)
by the logarithm of the birth year. *)

     declare current-student cursor for

               select  BIRTH-YEAR

               from  STUDENT

               where   MAJOR-DEPARTMENT-MAIN-NAME  =
                    `Management';

     open current-student;

     repeat

          fetch current-student into :birth-year;

          birth-year := log (birth-year);

          if sqlstatus = not-found then

               update STUDENT

                    set BIRTH-YEAR = :birth-year

                    where current of current-student

     until sqlstatus = not-found

     b.   delete from table-name

          where current of cursor-name

Example 4-70.

(* Display the name of every student; prompt the user  whether
the  student  should  be deleted; if the user replies `yes' --
delete the student. *)

     declare current-student cursor for

               select LAST-NAME, FIRST-NAME

               from  STUDENT

     open current-student;

     repeat

          fetch current-student into :last-name, :first-name;

          if sqlstatus = not-found then begin

               writeln (` Would you like to delete ', last-
                    name, ` ', first-name, `?');

               readln (answer);

               if answer=`yes' then

                    delete from STUDENT

                         where current of current-student

               end

     until sqlstatus = not-found

4.5.   Expressive Power of Relational Query Languages

Ignoring minor differences in expressiveness, such as  the  output  of
identical  rows,  the  following  languages  have  approximately equal
power.  A query that can be expressed in  one  language  can  also  be
expressed in the others:

 o   Tuple-oriented Relational Calculus without aggregate functions

 o   Relational Algebra

 o   SQL without aggregate functions

The aggregate  extension  of  the  Predicate  Calculus  and  SQL  with
aggregate functions have a higher power.

The  structured  extension  of   Pascal,   being   a   general-purpose
programming language, has a much higher power of expressiveness.


Reference Schemas
The following are the semantic and relational schemas for the university case study application. These schemas are referred to in most of the examples in this text.


Figure Ref-1. A semantic schema for a university application.


Figure Ref-2. A relational schema for the university application.