Introduction to Access SQL

Introduction

This document aims to describe the SQL (Structured Query Language) generated by Microsoft Access when using the QBE interface. By looking at different types of queries, one can teach oneself SQL. This document aims to describe the purpose of each SQL clause and how it all fits together.

Although most of the time one need not be exposed to SQL in Access it can be useful to understand the structure of SQL and when it generates clauses and extra brackets unexpectedly. It is also useful to know how Access SQL differs from standard SQL, in case one is transferring the database to another package such as Oracle.

Knowing about SQL in Access is useful when:

SQL commands

SQL commands are used to create, query and maintain a database. A query can contain only a single SQL command. The command is terminated by a semicolon.

Retrieving data from the database to display is the most common SQL operation, and to perform this the select command is used. The basic select command has two parts (clauses):

select the data (field names or expressions) to display
from a table or some tables (table names) from where the data comes

The select clause is always entered first, and is immediately followed by the from clause. It can also specify conditions for selecting records, ordering, grouping and joins between tables. A Full list of SQL clauses is given at the end of this document

Example database

The example database used in this document has the following 5 tables:

Patients
Drugs
Doctors
Treatment
Diagnosis

The data consist of details of each patient (date of birth, sex etc), doctor, drugs available and details of treatment. The patients are identified by a reference number (PatientlD). By splitting the data like this, duplication of details such as drug name is avoided (see also Access query language elements (document acc-r4).

The queries used are the same as those in Using Access queries (document acc97-t4).

Looking at the SQL of a query

To see the SQL that is generated when using Access queries:

SQL can also be typed in if one selects SQL Specific from the Query menu but one must be aware that converting to a Select query later will mean that the SQL is lost and it can not be looked at with the grid. SQL specific is really only used when one wants to use SQL to create tables, send SQL to a non-Access database system or create more complex queries

Looking at the SQL of a table lookup box

Looking at the SQL of a combo box or listbox

Looking at the SQL of a graph

Example 1 - query using the Sort option and Top Values

List all the details of all the patients in ascending order of family name:

Field

Patients.*

Family name

Table

Patients

Patients

Sort

 

Ascending

Show

  ü  

Criteria

   

Creating a query using more than one table

Example 2 - query using multiple tables

Find which drugs were taken by which gender:

Field

Drugname

Dosage

Gender

Table

Drugs

Treatment

Patients

Sort

 

 

 

Show

ü   ü   ü  

Criteria

 

 

 

Selection criteria

The Criteria and Or field options are used to specify whether you want the query to include or exclude -information based on the contents of a field. Note that Access inserts hashes (#) around dates -this confirms that Access recognises them as date strings (see date handling). Quotes are automatically placed around the text strings. Numeric criteria do not have quotes or hashes around the number. Field names are enclosed by square brackets.

Example 3 - query using selection criteria

Find the female patient born on 22 November l942 whose ID is less than or equal to 10.

Field

PatientlD

Title

Family name

Gender

Date of Birth

Table

Patients

Patients

Patients

Patients

Patients

Sort

 

 

 

 

 

Show

  ü   ü   ü   ü   ü

Criteria

<=10

 

 

"f"

#22/11/42#

Operators

Operators can be used to construct selection criteria for queries. Operators are:

 

And

Combines expressions. For the combined expression to be true, each of the component expressions must be true.

"Smith" and "Jones"

Or

Combines expressions. For the combined expression to be true, any one of the component expressions must be true.

"Smith" or "Jones"

XOr

Combines expressions. For the combined expression to be true, only one of the component expressions must be true.

"Smith" xor "Jones"

Between

Tests whether a value falls within a range.

between 0 and 10

Like

Tests whether the entry in a text field matches a pattern.

like "Ch*"

In

Tests whether an entry is an item in a set.

in (50, 100, 200)
in ("Bristol", "Bath")

Not

Negates an expression.

not <100

Is null

Tests whether a field is empty (used as a selection criterion)

is null

Is not null

Tests whether a field is not empty.

Is not null

Example 04 - query using criteria in different fields

Find patients who live in Bristol or who are female:

Field

Given name

Family name

Gender

Town

Table

Patients

Patients

Patients

Patients

Sort

 

 

 

 

Show

  ü   ü   ü   ü

Criteria

 

 

"f"

 

Or

 

 

 

"Bristol"

Example 05 - query using criteria in the same fields

Find patients who live in Bristol or Bath:

Field

Given name

Family name

Town

Town

Table

Patients

Patients

Patients

Patients

Sort

 

 

 

 

Show

  ü   ü   ü   ü

Criteria

 

 

"Bristol"

 

Or

 

 

 

"Bath"

Example 06 - query using Like

Find the patients whose name starts with "m" and postcode starts with B and then any letter between A and S then a single digit and a space:

Field

PatientID

Family name

Postcode

Town

Table

Patients

Patients

Patients

Patients

Sort

 

 

 

 

Show

  ü   ü   ü   ü

Criteria

 

m*

B[A - S]# *

In ("Bristol","Bath")

Example 07 - testing for unknown values

List the patients with no town given.

Field

PatientID

Family name

Town

Sort

 

 

 

Show

ü ü ü

Criteria

 

 

is null

Creating a parameter query

A parameter query (or prompted query) is a type of select query which is useful if you frequently run the same query but change the criteria each time you run it. Once the query is created you can re-run it without opening the query window or making changes in the QBE grid; instead Access prompts you for criteria in the Enter Parameter Value dialog box. You can specify as many criteria as you want. (Parameter queries are particularly good when used as filters with forms.)

Example 08 - prompted query

List the patients for a given town:

Field

Initials

Given name

Family name

Town

Table

Patients

Patients

Patients

Patients

Sort

 

 

 

 

Show

ü ü ü ü

Criteria

 

 

 

 

Or

 

 

 like [first few letters of surname]&"*"

[Whichtown]

Calculations in queries

You can perform calculations on groups of records using queries called aggregate queries. Expressions are typed in the Field box instead of fieldnames. The functions available for these queries include: Sum, Avg, Min, Max, Count, StDev, First and Last. Domain aggregate functions (name starts with 'd'), dsum, davg etc are used when calculating statistics over a subset of values on a form or report, not a select query. See Help/aggregate functions/calculate d fields.

Example 09 - using aggregate functions

To find the average number of tablets and the most in a packet of drugs using the Drugs table:

Field

Average no of tablets:
Avg([tablets per packet])

Most in packet:
Max([tablets per packet])

Table

   

Sort

   

Show

ü ü

Criteria

   

SELECT DISTINCT DAvg([tablets per packet],
FROM Drugs;

Calculations on groups of records

It is possible to run a query that calculates values for each group of records for example, for the patients who all come from the same town. To do this you need to specify the fields to use with the GroupBy option, and the fields to use f or the aggregates by specifying a calculation (Sum or Avg for instance).

Example 10 - calculation on a group

Find how many patients there are in each town:

Field

Town

Number of Patients: PatientID

Town

Table

Patients

Patients

Patients

Total

Group By

Count

Count

Sort

 

Descending

Descending

Show

ü ü  

Criteria

     

Example 11 - setting criteria on aggregate queries

Find the towns whose name start with B and which have more than 3 patients. Display in order of size:

Field

Town

count: PatientID

Town

Town

Table

Patients

Patients

Patients

Patients

Total

Group By

Count

Group By

Where

Sort

 

Descending

Ascending

 

Show

ü ü    

Criteria

 

>3

 

Like "B*"

Arithmetic expressions

You can use arithmetic expressions in queries (+, -, * (multiplication) and / (division)). Note that if one of the fields used for multiplying and dividing has a null value or has a null value then the result of the whole expression will b e null.

Example 12 - query using arithmetic

Find the cost per tablet of each drug:

Field

Drugname

Tablets per packet

Cost per packet

Cost_per_tablet:
[Cost per packet]/[tablets per packet]

Table

Drugs

Drugs

Drugs

 

Sort

       

Show

ü      

Criteria

 

>0

   

Example 13 - unique values

Find the different towns that patients come from:

Field

Town

Table

Patients

Sort

 

Show

ü

Criteria

 

Example 14 - character function

Display the towns that people come from in capital letters:

Field

towns: UCase([Town])

Table

Patients

Sort

 

Show

ü

Criteria

 

The iif function

You can also use iif to return more meaningful values than are stored in the database, and to do calculations based on the field value.

iif requires the name of the field or an expression, followed by the criteria, and the values to be returned if true and false. In the example below, if gender is m, "male" is returned, otherwise "female" is returned.

If you use a mathematical operator to find a value and one of the fields is blank, the result is a null value. To prevent this you can use the iif function to check and produce an error message, for instance if a date is missing from a field used in a calculation, the message might ask you to check for a missing date. A new function in Access 97 is nz which may also be used.

Example 15 - iif

Use iif to expand the values "m" and "f" to "male" and "female" in the output:

Field

gendername:iif (Gender="m", "male", "female")

Gender

PatientID

 

Table

 

Patients

Patients

 

Sort

 

 

 

 

Show

ü ü ü

 

Criteria

 

 

 

 

Example 16 - group iif

Find, for each drug, the dosage by each gender:

In this example the clause: iif(gender,"m", dosage, null) selects the dosage if gender = "m"; otherwise the value is set to the null value and is not included in the calculation of the average.

Field

Drug name

maledose: Iif([Gender]='m',[dosage],Null)

femaledose:Iif([Gender]='f',[dosage],Null)

Table

Drugs

 

 

Total

Group by

Avg

Avg

Sort

Ascending

 

 

Show

ü ü ü

Criteria

 

 

 

  • An alternative is to use the Crosstab query wizard with Example 2 - query using multiple tables (the wizard can only be used on a single table or query and we want to incorporate fields from 3 tables.

    Field

    Drugname

    Gender

    The Value: Dosage

    Row Summary: Dosage

    Table

    Example 2 - query using multiple tables

    Example 2 - query using multiple tables

    Example 2 - query using multiple tables

    Example 2 - query using multiple tables

    Total

    Group By

    Group By

    Avg

    Avg

    Crosstab

    Row Heading

    field Heading

    Value

    Row Heading

    Sort

    Ascending

         

    Show

    ü ü ü ü

    Date handling

    Dates can be displayed in different formats which are specified in the Field row.

    The format function specifies the date format using keywords, for example "Dddd". The case of the keyword specifies the case of the output, for example "MMMM" outputs the month name in capital letters.

    Arithmetic can be performed on dates using the DateDiff function.

    Example 17 - dates

    To display the dates in a different format:

    Field

    Family name

    Date of Birth

    Formatted date:
    Format([Date of Birth], "dddd Mmmm d")

    Year of Birth:
    format([date of birth], "yyyy")

    Sort

           

    Show

    ü ü    

    Example 18 - date calculation

    To find the age of each patient:

    Field

    Date of Birth

    Age:DateDiff("d",[Date of Birth],Now())/365.25

    Months:DateDiff("m",[Date of Birth],Now())

    Table

    Patients

     

    Patients

    Sort

     

     

     

    Show

    ü ü ü

    Example 19 - range of values

    Find how many patients are in the specified age ranges:

    age_range

    age_min

    age_max

    1-10

    1

    0

    11-20

    11

    20

    21-30

    21

    30

    31-40

    31

    40

    41-50

    41

    50

    51-60

    51

    60

    61-70

    61

    70

    71->

    71

    99

    Field

    age_range

    PatientID

    DateDiff("m",[birth_date],Now())/12

    Table

    age_range

    Patients

     

    Total

    Group By

    Count

    where

    Sort

     

     

     

    Show

    ü ü

     

    Criteria

     

     

    between age_min and age_max

    Queries within queries

    Queries within queries (nested queries or sub-queries) are queries which use SQL select statements inside another query. The select statement has a "select" clause to specify the names of the fields, a "from" clause to specify the name of the tables used and an optional "where" clause to specify criteria. The select statement must be enclosed in parentheses.

    Example 20 - nested query

    Find the drug used which had the biggest dosage and give the dosage:

    Field

    Drug name

    Dosage

    Table

    Drugs

    Treatment

    Sort

     

     

    Show

    ü ü

    Criteria

     

    (select max(dosage) from treatment)

    Calculating percentages

    Complex queries can be simplified by using other queries to query them. Having created a query it can then be treated in the same way as a table.

    Example 21 - calculating a percentage

    Find the number of doses that have been taken for each drug, and the percentage of the total number:

    Field

    Drug name

    Drug_cost:sum(dosage*[cost per packet]*[doses per day])

    Table

    Drugs

    Treatment

    Total

    Group by

    count

    Sort

    Ascending

     

    Show

    ü ü

    Field

    Total_cost:sum(dosage*[cost per packet]*[doses per day])

    Table

    Treatment

    Sort

     

    Show

    ü

    Field

    Drug name

    Drug_cost

    Percent:drug_cost/total_cost

    Table

    Drugs

     

     

    Sort

    Ascending

     

     

    Show

    ü ü ü

    Unmatched query

    There are three kinds of join between tables. The default is for the query to only include records from both tables that share a common value for a field. Thus a query on the DRUG and TREATMENT table will only list those drugs that have been used in treatments. This is the equi-join or inner join.

    The second way is to include records from the primary table regardless of whether or not a record matches a record in the other table. Thus, drugs can be listed regardless of whether they have been used in treatments or not. This is the left outer join.

    The third way is to include records from the other table regardless of whether or not a record matches a record in the primary table. Thus, the query can display all treatment records regardless of whether they have details in the drug table. This would break referential integrity since it should not be possible to prescribe a drug if it was unknown. Thus unmatched queries can also be useful when one is trying to set up referential integrity between two tables. This is a right outer join.

    Example 22 - unmatched query

    Find the drugs not used in treatment :

    Field

    DrugID

    Drugname

    DrugID

    Table

    Drugs

    Drugs

    Treatment 

    Sort

    Ascending

     

     

    Show

    ü ü  

    Criteria

       

    is null

  • there are other ways of doing this query using:

    not exists operator

    The not exists operator can also be used as can be seen in the next example (far more efficient than the not in operator since it uses indexes

  • if you put not exists in the criterion grid you will get a type mismatch error unless you put the criterion on the join field DrugID since unexpectedly generate:
  • not in method

    Union Query

    The following query can only be done if one knows SQL. It shows Diagnosis and Treatment records for each patient.

    Action queries

    Action queries enable you to make large numbers of similar changes to a database easily. There are 3 types of action query:

    Delete

    deletes records from a table

      delete from Drugs where drug_name="Smarties"

    Append

    adds a group or records from one or more tables to another table or tables

      insert into Drugs (DRugID)
      select distinct drugid
      from treatment
      where not exists (select * from drug where drug.drugid=treatment.drugid)

    Update

    changes the data in a specified group of records. It advisable to run some tests to make sure your update query performs satisfactorily before using it to change a large number of records. It is also advisable to backup your database before running an update query.

      update drugs
      set [cost per packet]= [cost per packet]*1.1
      where [tablets per packet]>50

    Creating and listing tables

    Microsoft Access tables are normally built using Table button, but one can create a table using SQL by creating a new query, not adding any tables. You must select 'SQL specific' from the 'Query' menu' Then choose 'data definition'. Note that the datatypes are given as: text, datetime, byte, short, integer, single, double, binary, boolean, currency

    The SQL command create table creates a table. For example, to create the example database tables:

    create table Drugs(
    DrugID text(6) constraint drugtablekey primary key,
    Drugname text(40) not null,
    Tablets_per_packet integer,
    Cost_per_packet currency;