Professional Documents
Culture Documents
Practical workbook
Course files
This document and any associated practice files (if needed) are available on the web. To find these, go to www.bristol.ac.uk/is/learning/resources and in the Keyword box, type the document code given in brackets at the top of this page.
Related documentation
Other related documents are available from the web at: http://www.bristol.ac.uk/is/learning/resources
Introduction to Access SQL (November 05) 2010 University of Bristol. All rights reserved.
Contents
Format conventions Related documentation Task 1 SQL commands ............................................................................... 1 Example database ........................................................................... 1 Looking at the SQL of a query ...................................................... 2 Looking at the SQL of a table lookup box .................................... 2 Looking at the SQL of a form combo box or listbox.................... 3 Looking at the SQL of a graph ...................................................... 3 Query using the Sort option and Top Values ............................... 4 Create SQL from scratch ............................................................... 4 Minimum SQL- list all fields of a single table .............................. 4 Query to list all fields of a single table and specify sort order .... 5 Unique Records ............................................................................... 6 Top Records ..................................................................................... 6 Unique values .................................................................................. 7 Create your own query using SQL only........................................ 7 Simple selection criteria.................................................................. 8 Query using selection criteria on different types of data ............. 8 Using criteria in different fields with the or operator .................. 9 Query using criteria in the same field with the or operator ...... 10 Expressions and functions ............................................................ 12 Query using arithmetic ................................................................. 12 Aggregates on groups of records ................................................. 14 Calculation on a group ................................................................. 14 Setting criteria on aggregate queries ........................................... 15 Creating a query using multiple tables ....................................... 17 Query using two linked tables ...................................................... 17 Query using three linked tables ................................................... 19 Using SQL Specific in a Query .................................................... 20 Create your own query ................................................................. 21
Task 2
Task 3
Task 4 Task 5
Task 6
Task 7
Further examples of SQL ........................................................................................ 22 Task 8 More criteria.................................................................................. 23 Query showing the use of the > operator .................................... 23 Query showing the use of the between operator ......................... 23 Query using Like ........................................................................... 23 Testing for unknown values ......................................................... 25 Creating a parameter query......................................................... 26 Prompted query............................................................................. 26 Create your own query using SQL only...................................... 26
Task 9
Task 10 Action queries ................................................................................ 27 Task 11 The iif function .............................................................................. 28 Using iif .......................................................................................... 28 Group iif ......................................................................................... 28 Task 12 Crosstab Query ............................................................................. 30 Task 13 Date handling ................................................................................ 32 Date format .................................................................................... 32 Date functions ................................................................................ 32 Age calculation .............................................................................. 32 Task 14 Define your own group values...................................................... 34 Task 15 Queries within queries .................................................................. 36 Nested query .................................................................................. 36 Task 16 Calculating percentages ................................................................ 37 Task 17 Unmatched query .......................................................................... 39 not exists operator ......................................................................... 40 not in method ................................................................................. 40 Task 18 Creating tables............................................................................... 41 Task 19 Table Constraints .......................................................................... 42 Task 20 Create an index.............................................................................. 43 Appendix A SQL syntax .................................................................................... A-1 Standard SQL select statement ................................................. A-1 Access SQL syntax ..................................................................... A-1 Delete statement ......................................................................... A-2 INSERT command ..................................................................... A-2 UPDATE command ................................................................... A-2 Data dictionary .............................................................................. B-1
Appendix B
Introduction
This document describes the SQL (Structured Query Language) generated by Microsoft Access when using the QBE interface. By looking at different types of queries, you can teach yourself SQL. This document describes the purpose of each SQL clause and how it all fits together. Although most of the time the user 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 you are transferring the database to another package such as Oracle. Knowing about SQL in Access is useful when: Looking at the source of a combo box. As the source is given in SQL, you could also change the ordering or add a conditional clause. Looking at the source of a graph. As the source is given in SQL, you also could add a conditional clause or copy a graph, and change the base table or query. A query is not doing what is expected. You want to create similar queries based on different tables or update a query when the table name has been changed. It can be easier to copy the original query, and change the name of the table using the SQL view. You want to do a union query. This is a special type of query that can only be constructed if you know SQL.
Prerequisites
You should have attended the course Using and designing Access databases (CC1ACC). This course is based on a thorough understanding of the query types learned on those two courses.
Example database
Open the database C:\Training\Access\SQL\Treatment for SQL. This example database has the following 5 tables: Patients; Drugs; Doctors; Treatment; Diagnosis
Figure 1 relationships
The data consists 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 (PatientID). By splitting the data like this, duplication of details such as drug name is avoided. The queries used are the same as those in Making more of queries (document acc23) and the same type as those demonstrated on the course Using and Designing Access databases (document acc2).
Introduction to Access SQL (acc-8) 1
Open the Patients form in form view. Look at the dropdown box for the doctor for several patients. Only doctors of the same gender as the patient are displayed. Look at the design view of the form and at the Row Source Property of doctor: SELECT [Doctors].[DoctorID], [Doctors].[Family name], [Doctors].[Given name], [Doctors].[Initials], [Doctors].[Title], [Doctors].[Internal telephone], [Doctors].[gender] FROM [Doctors] where gender=Forms!Patients!gender order by [family name]
Note that the semi-colon at the end of the SQL statement is optional on a form, but compulsory on a query or in a module and indicates the end of the query. It is good practise to always include it if in doubt.
An SQL select command can have many clauses - which must be specified in a particular order (see the syntax at the end of this document). As a minimum, it must specify which fields are to be selected from which tables: The select clause specifies the fields or expressions to be displayed (the fields are separated by commas; * means all fields) and the from clause specifies which table(s) they are to be taken from. The field name will appear in the select clause only if Show is ticked in the query design. SQL commands can continue over more than one line in a query. They are terminated by a semicolon in a query. Fieldnames and tablenames which include a space or arithmetic operator etc, will have the name enclosed by square brackets to show where the name begins and ends. The fieldnames are preceded by the tablename by default, for example Patients.*, Patients.[Family name]. In actual fact, the field names only need to prefixed by the table name if the same field name appears in a query involving more than one table and the name of the field is in both tables.
Query to list all fields of a single table and specify sort order
2.4 Create a query using the normal grid as follows: (Open the query Example 02a) Create a query to list all the details of all the patients in ascending order of family name (add the family name field as a no show field since it is already being shown): Field Table Sort Show Criteria Save your query. 2.5 Look at the SQL: SELECT Patients.* FROM Patients ORDER BY Patients.[Family name]; The order by clause specifies which fields govern the order in which the records are displayed. By default order by gives ascending order. See what happens to the SQL when you specify descending order. Patients.* Patients Family name Patients Ascending
The asc and desc operators specify whether the ordering is ascending or descending. The default is asc. The order by clause is always the last clause. Note the square brackets around [Family name] since it contains a space. Square brackets are used to determine field names and table names, for example, [Date of Birth] since including spaces and operators is .allowed for names (but not advisable!)
Unique Records
2.6 Look at the properties of the query by right-clicking the area where the tables are displayed. By default, Unique Records and Unique Values are both set to No. Change Unique Records to Yes. 2.7 Look at the SQL: SELECT Distinctrow Patients.* FROM Patients ORDER BY Patients.[Family name]; DISTINCTROW has been added to the select clause. Note that DISTINCTROW may be added automatically to the SQL (particularly in combo boxes). This indicates that data based on duplicate entire records will not be displayed more than once, but data duplicated on just the selected fields will. In practice, if one has set a primary key, there will be no duplicate records. For example, if one is just displaying the gender field, m and f will be displayed as many times as there are patients. Task 2.11 shows how to display distinct values on selected fields (just show m and f once).
Top Records
2.8 Select the first 5 patients by clicking on the design button to return to the query design window, then use the dropdown box on the Top Values button (the All button on the toolbar) to select the first 5 patients. (By default, the defaults value shown is All). Look at the SQL: SELECT DISTINCTROW TOP 5 Patients.* FROM Patients ORDER BY Patients.[Family name]; Notice that in the query design, the dropdown box gave the option of looking as 5, 25, 100, 5%, 25% or All. By modifying the SQL directly you can specify the exact number you wish to see.
2.9
Notice the TOP descriptor in the SQL and alter the SQL to look at the first 7 patients. In the query design, select the first 5% of the patients, by using the Top Values button on the grid toolbar.
2.10
Look at the SQL: SELECT TOP 5 PERCENT Patients.* FROM Patients ORDER BY Patients.[Family name]; Notice the PERCENT descriptor used in conjunction with the TOP descriptor. Save the query.
Unique values
2.11 Find the different towns that patients come from: Field Table Sort Show Criteria Change the property of the query for Unique Values to Yes 2.12 Look at the SQL: SELECT DISTINCT Patients.Town FROM Patients; DISTINCT displays unique values of the fields being displayed (more useful than Distinctrow). Open the query and show the SQL you created in Task 2.10 and copy it. Open Notepad, paste in the SQL and change all occurences of Patients to Doctors. Paste the new SQL back into the query and run. The above shows how a knowledge of SQL can help you to create similar queries on different tables. This is much easier than rebuilding the query. Town Patients
Comments
Boolean Operators
You will see the use of some of the following Boolean operators: And Combines expressions. For the combined expression to be true, each of the component expressions must be true. Lastname="Smith" and Firstname="Jane"
Or
Combines expressions. For the combined Lastname="Smith" or expression to be true, any one of the component Lastname="Jones" expressions must be true. Combines expressions. For the combined expression to be true, only one of the component expressions must be true. Lastname="Smith" xor Firstname="Jane"
XOr
3.2
Look at the SQL: SELECT DISTINCTROW Patients.PatientID, Patients.Title, Patients.[Family name], Patients.Gender, Patients.[Date of Birth] FROM Patients WHERE (((Patients.PatientID)<=10) AND ((Patients.Gender)="f") AND ((Patients.[Date of Birth])=#11/22/42#)); A where clause is included in the select command after the from clause to choose only records which fit specified criteria. The and operator between two criteria means both criteria must be true. If no operator is given in the where criteria grid, then "=" is used. You can use <, <=, >, >= , <> and "between..and.." on text, date and numeric fields. Text searches are not case sensitive. Quotes are placed automatically round text to be searched (double by default but one can use single quotes). Date values need to be surrounded by #. This enables the user to type the date in whatever format is most familiar and it will then be converted into a form that Access can handle. Numeric criteria do not need quotes or a hash around the number. Round brackets (most are unnecessary) are used around each where condition to determine order of precedence, and around functions, for example, avg(Fees).
Note
3.4
Look at the SQL: SELECT Patients.[Given name], Patients.[Family name], Patients.Town, Patients.Gender FROM Patients WHERE (((Patients.Town)="bristol")) OR (((Patients.Gender)="f")); The or operator includes all entries where one or the other (or both) of the conditions is true. Round parentheses must be used to indicate order of precedence particularly when and and or conditions are used together. For example, to find males from Bristol and females from Bath. (Patients.Town="bristol" and gender="m") OR (Town="Bath" and Patients.Gender="f")
10
11
4.1
If one of the fields used for multiplying and dividing has a null value then the result of the whole expression will be null.
Look at the SQL: SELECT Drugs.[Drug name], Drugs.[Tablets per packet], Drugs.[Cost per packet], [Cost per packet]/[tablets per packet] AS cost_per_tablet FROM Drugs WHERE (((Drugs.[Tablets per packet])>0)); Arithmetic expressions can be used in the select as well as the where clause. The cost per tablet for each drug is calculated by dividing the cost per packet by the number of tablets per packet. The as clause gives a name to the resulting expression (default expr1 which appears before the : in the grid). Character function 4.3 Display the towns that people come from in capital letters: (Open the query Example 05b) Field Table Sort Show Criteria towns: UCase([Town])
12
4.4
Look at the SQL: SELECT DISTINCT UCase([Town]) AS towns FROM Patients; The UCase function converts values to upper case. Access changes the name of the function from ucase to UCase but case has no significance so it does not matter how you type it. Remember to name the heading of the field differently to the name of the field otherwise you get a circular alias message.
Note
Use Access query language elements (document acc-r4) to see what other functions are available.
13
Calculation on a group
5.1 Find how many patients there are in each town ordered by the biggest population: (Open the query Example 07a) Field Table Total Sort Show Criteria Town Patients Group By Number of Patients: PatientID Patients Count Descending Town Patients Count Descending
14
5.2
Look at the SQL: SELECT Patients.Town, Count(Patients.PatientID) AS [Number of patients], Count(Patients.Town) AS CountOfTown FROM Patients GROUP BY Patients.Town ORDER BY Count(Patients.PatientID) DESC , Count(Patients.Town) DESC; Note the new group by clause finds the unique values of the fields given in it. The group by clause always follows the where clause if there is one. Since there is no where clause in the example above, then it follows the from clause. The group by field option on the Town field operates with the Count function on the patient ID to divide all the patients into groups based on the town in which they live. Count is then applied to the rows in each group. Note that some patients do not have a town as part of their address. The group by clause must contain the same fields as the select clause, except for the fields that hold aggregates, and in the same order. Thus, in the example, the group is on town, so the select clause and the group by clause both work on the town field to find the unique values of town. The count functions in the select clause then show the counts for each town. Count should be applied on the Primary key (PatientID) to give the number of patients for each town including those patients where the town is unknown. Applying the count on town shows 0 for unknown towns, so if you want to get a count of how many unknown values there are, count on the primary key. The order by clause orders output, in ascending order by default. It is possible to order on a count as well a field. If the field to be ordered has an alias, the alias can be given in the order by clause. The order by clause must follow the group by clause. Note that the order clause has been added because the sort field has been specified on the grid. order is normally the last clause of a select statement (unless the with owner access option has been used or it is a crosstab query). If the grouping is to be done on more than one field, the field specifications are separated by commas.
15
5.4
Look at the SQL: SELECT Patients.Town, Count(Patients.PatientID) AS count FROM Patients WHERE (((Patients.Town) Like "B*")) GROUP BY Patients.Town, Patients.Town HAVING (((Count(Patients.PatientID))>3)) ORDER BY Count(Patients.PatientID) DESC , Patients.Town; The new having subclause of the group clause limits the number of groups used. having clause always appears after the group clause and cannot be used without a group by clause. The having criteria should normally be used on the aggregate function fields such as avg, sum etc since it works on the aggregate value not the individual record value unlike the where clause. It is important to distinguish between testing for a field value and an aggregated value. This is demonstrated by the use of the where clause to perform criteria on individual field values, where it is used to filter out records before aggregation, that is towns whose name start with B. The having criteria checks the result of an aggregated function, that is more than 3 patients. Do NOT put town like "B*" in the having clause but in the where clause. Although putting the criteria in the having clause will give the correct answer it is very inefficient since the query has to select all the records before it aggregates them and then filter out the towns not starting with B. Putting the criteria in the where clause makes sure that the non-B records are filtered out before the aggregation is done so it has far less work to do. Town appears in the grid three times because the ordering is done on the count and then the town, but the town was to be displayed first. Town then appears so that the criterion of towns starting with the letter B can be set. Normally one would expect the group fields to reflect the none aggregated fields on the select clause. The SQL is more understable than the grid! Order by can be used on aggregate functions as well as field values. The query Example 07c is another example of this type of query.
16
17
6.2
Look at the SQL: SELECT DISTINCTROW Drugs.[Drug name], Sum([Dosage]*[cost per packet]*[doses per day]) AS drug_cost FROM Drugs INNER JOIN Treatment ON Drugs.DrugID = Treatment.DrugID GROUP BY Drugs.[Drug name]; When data from more than one table is selected by a query, the tables must be joined using the common linking fields. Note the inner join clause on the drugs table to the treatment table. The inner join clause has come from linking the tables by drawing a line between the two tables. It signifies an equi-join (to only display the combined record if there are matching fields in both records). This is a non-standard SQL clause to link the two tables. The structure of the inner join clause first identifies the two tables to be joined and then gives the joining fields after the on clause. Inner join is part of the from clause so appears before a where clause. If one wanted to use standard SQL, a where condition would be added not by drawing a line between the linking fields, but by using the criteria box instead, for example, in the TREATMENT.DrugID field specification, add the criteria [DRUGS].[DrugID]. This results in a where clause instead of an inner join clause. The where clause must appear after the from clause. You must add the square brackets otherwise Access assumes that you are looking for text and helpfully adds double quotes! From Drugs, treatment where [Drugs].[DrugID] = [Treatment].[DrugID] It is more efficient to specify the join conditions before any other conditions in the where clause. If the field name is unique to a particular table (for example 'Drug name'), the table name need not be specified. If the field name appears in more than one table being queried, it must be prefixed by the table name.
18
6.4
Look at the SQL: SELECT Patients.Gender, Treatment.Dosage, Drugs.[Drug name] FROM Drugs INNER JOIN (Patients INNER JOIN Treatment ON Patients.PatientID = Treatment.PatientID) ON Drugs.DrugID = Treatment.DrugID; In this example, data is selected from the Drugs, Patient and the Treatment tables. In this case the common linking fields are PatientID and DrugID which is shown by the inner join clause. Round brackets identify the joins and it can get really hard to unravel what is being joined to what. Start at the most embedded join (inside the most brackets) - so Patients and Treatments are joined first on PatientId, and then Drugs to Treatment on DrugID. If one wanted to use standard, more understandable SQL, the statement would read: SELECT Patients.Gender, Treatment.Dosage, Drugs.[Drug name] FROM Patients, Drugs, Treatment where [Drugs].[DrugID] = [Treatment].[DrugID] and Patients.PatientID = Treatment.PatientID
19
7.1
Create a new query in design view and cancel the Add table window. Look at the query types from the Query menu and note the choice of Pass through, data definition or union. Pass-through. This query can return records, be used to change data, create a database object, or perform an action as an action query does. This type of query sends commands directly to ODBC databases, such as Oracle. The SQL must be the same SQL as the database you are using. Thus, if the SQL is being used to query an Oracle database (perhaps because the query cannot be performed using Microsoft Access), then the SQL must be Oracle SQL (which can differ greatly from Microsoft SQL). Data Definition. Use SQL data definition queries to create, delete, or alter tables; or create indicies in the current database, (particularly if you are linking to tables in another database that for example, does not have a primary key). Each data-definition query consists of just one datadefinition statement. Microsoft Access supports these data-definition statements: CREATE TABLE creates a table; ALTER TABLE adds a new field or constraint to an existing table; DROP deletes a table from a database or removes an index from a field or group of fields; CREATE INDEX creates an index for a field or group of fields. Union. This type of query combines fields from two or more queries into a single query. The two select queries must have the same number and type of fields, and the fields must be in the same order. It eliminates duplicate rows. For example, if you have one query that lists individual treatments and another that lists the totals for each drug, you can combine these lists into one result set using a union query.
20
Open the query Example 11a. This is a union query and combines Diagnosis and Treatment records for each patient, including the doctor details. 7.2 Look at the SQL: SELECT Patients.PatientID, [Patients].[Given name] & " " & [Patients].[Family name] AS patient, [Doctors].[Title] & " " & [Doctors].[Family name] AS doctor, Diagnosis.[Date seen] as date_happening, Diagnosis.diagnosis FROM Patients INNER JOIN (Doctors INNER JOIN Diagnosis ON Doctors.DoctorID = Diagnosis.DoctorID) ON Patients.PatientID = Diagnosis.PatientID UNION SELECT Patients.PatientID, [Patients].[Given name] & " " & [Patients].[Family name] AS patient, [Doctors].[Title] & " " & [Doctors].[Family name] AS doctor, Treatment.[Date start course] as date_happening, Drugs.[Drug name] FROM Doctors INNER JOIN (Drugs INNER JOIN (Patients INNER JOIN Treatment ON Patients.PatientID = Treatment.PatientID) ON Drugs.DrugID = Treatment.DrugID) ON (Doctors.DoctorID = Treatment.DoctorID) AND (Doctors.DoctorID = Treatment.DoctorID) ORDER BY Patients.PatientID, date_happening; Union combines the rows returned by two select statements. It is easier to construct this type of query by creating the first part of the query, then creating the the second, adding the union operator and then copying and pasting the SQL of the first query onto the second. The number of fields in the two select clauses must be the same, and the data types of the selected fields must match. The as clause can be used to change the name of the resulting fields. By default, the resulting field should be the name of the field of the first slect clause. Thus, the last field is called diagnosis, the penultimate field is called date_happening. The last clause is the order by clause. This applies to the result of the whole query, not the integral parts so there is only one ordering clause. Note the new icon for the union query in the database window.
21
22
Tests whether the entry in a text field matches a like "Ch*" pattern Tests whether an entry is an item in a set Negates an expression Tests whether a field is empty (used as a selection criterion) Tests whether a field is not empty in (50, 100, 200) in ("Bristol", "Bath") not <100 is null Is not null
PatientID Patients
SELECT Patients.Initials, Patients.[Family name], Patients.Postcode FROM Patients WHERE (((Patients.[Family name]) Like "m*") AND ((Patients.Postcode) Like "B[A-S]#*")); Typing a wild card character such as * introduces the like operator. Access will change the criteria m* to like "m*". Like allows comparisons between strings using wild card characters and so is different to "=". * represents any number of any character. ? represents a single character. # represents a single digit. [A - S] represents any character between A and S. W[ae*] means starting with W followed by a or e then any other characters. W[!ae]* starting with W and not followed by a or e. *[*]* contains an asterisk. *[?]* contains a question mark.
24
25
Prompted query
9.1 List the patients for a given town: (Open the query Example 08a) Field Table Sort Show Criteria Or like [first few letters of surname]&"*" [Whichtown] Initials Patients Given name Patients Family name Patients Town Patients
The prompt is enclosed in square brackets, for instance "Which town?" (This should not be the name of a field otherwise Access compares it with the value of that field)
9.2
Look at the SQL: SELECT Patients.Initials, Patients.[Given name], Patients.[Family name], Patients.Town FROM Patients WHERE (((Patients.[Family name]) Like [first few letters of surname] & "*") AND ((Patients.Town)=[which town])); Note the parameter names enclosed in square brackets, just like the fieldnames which have spaces as part of the name.
26
27
Using iif
Use iif to expand the values "m" and "f" to "male" and "female" in the output. (Open the query Example 12a). Field Table Sort Show Criteria gendername:iif (Gender="m", "male", "female") Gender Patients PatientID Patients
11.1
Look at the SQL: SELECT IIf([Gender]='m','male','female') AS gendername, Patients.Gender, Patients.PatientID FROM Patients;
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. (Open the query Example12b) Field Table Total Sort Show Criteria
Introduction to Access SQL (acc-8) 28
11.2
Look at the SQL: SELECT Drugs.[Drug name], Avg(IIf([Gender]='m',[dosage],Null)) AS maledose, Avg(IIf([Gender]='f',[dosage],Null)) AS femaledose FROM Drugs INNER JOIN (Patients INNER JOIN Treatment ON Patients.PatientID = Treatment.PatientID) ON Drugs.DrugID = Treatment.DrugID GROUP BY Drugs.[Drug name]; This type of query calculates an average on records then groups the result by two different ways - one down the left side (the group by clause) and the other across the top (the aggregated functions). The field aliases Maledose and Femaledose are used to specify the field names.
29
30
12.1
TRANSFORM Avg([Example 09b query using multiple tables].Dosage) AS [The Value] SELECT [Example 09b query using multiple tables].[Drug name] AS Treatment, Avg([Example 09b query using multiple tables].Dosage) AS [Row Summary] FROM [Example 09b query using multiple tables] GROUP BY [Example 09b query using multiple tables].[Drug name] PIVOT [Example 09b query using multiple tables].Gender; Note the new transform and pivot clauses (non-standard SQL) which precede and follow the select statement: TRANSFORM aggregate function SELECT statement PIVOT pivotfield [IN (value1[, value2[, ...]])] Transform is the field that will have the function performed on it the value as shown in the grid. Transform is optional but when included it is the first statement in an SQL string. It precedes a SELECT clause that specifies the fields used as row headings and a GROUP BY clause that specifies row grouping. Optionally, you can include other clauses, such as WHERE. The values returned in pivotfield are used as field headings in the query's datasheet. For example, pivoting the sex figures would create two fields. You can restrict pivotfield to create headings from fixed values (value1, value2) listed in an optional IN clause. You can also include fixed values for which no data exists to create additional fields. Select specifies the vertical grouping. It is the row heading of the grid. Pivot specifies that for each unique value of that field, a new field will be shown, so one would choose a field with fewer unique values than one chose for the row heading to make display longer rather than wider. It is the colum heading of the grid. Row summary is the field with the function performed on it before being grouped by the field, that is average dose for each drug for each person as opposed to average dose for each drug for each gender.
31
Date format
To display the dates in a different format. (Open the query example14a) Field Family Date of name Birth Formatted date: Year of Birth: Format([Date of Birth], format([date of birth], "dddd Mmmm d") "yyyy")
Look at the SQL: SELECT Patients.[Family name], Patients.[Date of Birth], Format([Date of Birth],"dddd mmmm d ") AS [formatted date], Format([date of birth],"yyyy") AS Year FROM Patients; AS assigns a name to the calculated field.
Date functions
13.2 Examples 14b and 14c show further examples of date functions.
Age calculation
13.3 To find the age of each patient add the Patients table and insert the following fields and options. (Open the query Example 4d) Field Table Sort Show Date of Birth Patients Age:DateDiff("d",[Date of Age_round:int(DateDiff("d",[D Birth],Now())/365.25 ate of Birth],Now()))/365.25) Patients
32
13.4
Look at the SQL: SELECT Patients.[Family name], Patients.[Date of Birth], DateDiff('d',[Date of Birth],Now())/365.25 AS age, int(DateDiff('d',[Date of Birth],Now())/365.25) AS age_round FROM Patients; The date function DateDiff returns the difference in the given period (for example, "m" for months) between two dates. If two dates are subtracted using the minus (-) operator, the answer is given in days. The int function rounds the age down. Using "yyyy" as the interval does not give the correct age as only the year is considered, not the day and month.
33
14.2
See what happens if you group an explicitly specified age range. (Open the query Example15a) SELECT DateDiff('m',[DATE OF BIRTH],Now())/12, Count(Patients.PatientID) AS CountOfPatientID FROM Patients WHERE DateDiff('m',[DATE OF BIRTH],Now())/12 Between 20 and 30 GROUP BY DateDiff('m',[DATE OF BIRTH],Now())/12;
14.3
Using a query with the age_range table, the patients can then be grouped into each range. You would have to create a separate query for each range unless you did a parameter query but even then you can only look at one range at a time. Field Table Total Sort Show Criteria between age_min and age_max age_range age_range Group By PatientID Patients Count where DateDiff("m",[birth_date],Now())/12
34
14.4
Look at the SQL: SELECT age_range.age_range, Count(Patients.PatientID) AS CountOfPatientID FROM Patients, age_range WHERE (((DateDiff('m',[DATE OF BIRTH],Now())/12) Between [AGE_MIN] And [AGE_MAX])) GROUP BY age_range.age_range; The field name used in the order by clause must appear in either the select or the group by clause. The join is performed by the between criteria on the age expression, not by an inner join. The age-range field then shows the age range into which the patient falls. It is also easy to modify the age-range table later if the ages need to be regrouped. Age_min and age_max must have the same data type as each other and the same data type as the calculated field (in this case integer).
35
Nested query
Find the drug used which had the biggest dosage and give the dosage. (Open the query Example16a) Field Table Sort Show Criteria 15.1 Look at the SQL: SELECT Drugs.[Drug name], Treatment.Dosage FROM Drugs INNER JOIN Treatment ON Drugs.DrugID = Treatment.DrugID WHERE (((Treatment.Dosage)= (select max([dosage]) from treatment))); In this example, SQL carries out the select clause within the parentheses first (so finds the max dose first). The single value produced as a result of this selection is then used by the where clause of the first select clause. In Task 5 you specifically gave a particular count (>3) as the criterion for when to display the values. In this query you calculate the current maximum dosage and then use this as the criterion for the rest of the query. The inner query must produce a single value (maximum dosage) for the equality criterion of the outer query to work. If it produces more than one value you will get an error message At most one record can be returned. (select max(dosage) from treatment) Drug name Drugs Dosage Treatment
36
Look at the SQL: SELECT Drugs.[Drug name], Sum([Dosage]*[cost per packet]*[doses per day]) AS drug_cost FROM Drugs INNER JOIN Treatment ON Drugs.DrugID = Treatment.DrugID GROUP BY Drugs.[Drug name];
16.3
Create a second query as follows called Total_Cost using the Treatment table. This is to find the total dose. (Open the query example17b) Field Table Sort Show Total_cost:sum(dosage*[cost per packet]*[doses per day]) Treatment
37
16.4
Look at the SQL: SELECT Sum([Dosage]*[cost per packet]*[doses per day]) AS [total cost] FROM Drugs INNER JOIN Treatment ON Drugs.DrugID = Treatment.DrugID; This only returns one row and one column. Then create a query called Percent_Cost to find the percentages using the Each_Drug and Total_Cost queries. (Open the query Example17c). Field Table Sort Show Drug name Drugs Ascending Drug_cost Percent:drug_cost/total_cost
16.5
Look at the SQL: SELECT [Example 16a each drug].[Drug name], [Example 16a each drug].drug_cost, [drug_cost]/[total cost] AS [percent] FROM [Example 16a each drug], [Example 16b total cost]; Percentage found by dividing the cost of each drug by the total cost. This is a good example of showing how queries can be used to simplify queries Another method is to use fields as they are derived in the query. This however is not standard SQL. Example 14c shows the expression for cost: Sum([dosage]*[cost per packet]) and then the expression for percent: [cost]/[total cost] using the value for cost which was derived in the previous field. SELECT Drugs.[Drug name], Sum([dosage]*[cost per packet]) AS cost, [cost]/[total cost] AS [percent] FROM [Example 14b total cost], Drugs INNER JOIN Treatment ON Drugs.DrugID = Treatment.DrugID GROUP BY Drugs.[Drug name], [Example 14b total cost].[total cost];
38
SELECT Drugs.DrugID, Drugs.[Drug name] FROM Drugs LEFT JOIN Treatment ON Drugs.DrugID = Treatment.DrugID WHERE (((Treatment.DrugID) Is Null));
This is the SQL created using the Unmatched query wizard using the outer join method. Look at the join line between the two tables. It should have an arrow on it. Click on the join line to check the properties of the join.
39
The second DrugID field is from the Treatment table and is tested for not null since there are no treatments for that drug. Note LEFT JOIN indicates that drugs will be listed regardless of whether they appear in the treatment table. The first named table is the primary table. RIGHT JOIN would indicate treatment using unknown drugs (would then have to check Drug - DrugID is null). The first named table is still the primary table. There are other ways of doing this query: exists operator (more efficient and standard SQL) not in operator (less efficient but standard SQL).
The not in operator can also be used as can be seen in the next example (far more efficient than the not exists operator since it uses indexes.
not in method
(Open the query Example18c) SELECT Drugs.DrugID, Drugs.[Drug name] FROM Drugs WHERE DrugID not in (select DrugID from Treatment ); The not in method is very inefficient as no indexes are used so can be very slow if there is a lot of data.
40
41
19.1
Look at the SQL: alter table DRUGSSQL add constraint DRUGS_pk primary key (DrugID) ; This creates a primary key for the table alter table TREATMENT add constraint TREATMENT_fk foreign key(DrugID) references DRUGS(DrugID). The 'references' clause shows the relationship between the DRUGS and TREATMENT tables. DRUGS and TREATMENT are related by the field DrugId. DrugId in TREATMENT is the foreign key (one or more fields whose values are based on the primary key from another table and used to specify the relationship between two tables). Note that referential constraints are normally added by editing the relationships diagram in Access, and field validity is added by editing the properties of the table. Any query, form or report built can incorporate these constraints automatically, provided they were defined before the query, form or report was built. The foreign key ensures that records added to the treatment table will relate to a known Drug. If you add a foreign key, it must be the same as the primary key of the related table and the primary key clause must have been used on that table definition. Value constraint (which for example ensures that the field can contain only values between 1 and 4) cannot be used in Access SQL.
42
20.2
43
Appendix A
SQL syntax
SELECT [predicate] { * | table.* | [table.]field1 [, [table.]field2.[, ...]]} [AS alias1 [, alias2 [, ...]]] FROM table or query [, ...] [IN externaldatabase] [WHERE... ] [GROUP BY... ] [HAVING... ] [ORDER BY... ]
where predicate is all, any, distinct This shows the basic order of the SQL clauses.
A-1
Delete statement
PURPOSE: SYNTAX: DELETE [FROM] table [WHERE condition] WHERE deletes only rows that satisfy the condition. The condition can reference the table and can contain a subquery. If you omit this clause, Oracle deletes all rows from the table. Rows can only be deleted from one table at a time. To remove rows from a table. Use Delete action query to see this SQL.
INSERT command
PURPOSE: SQL. SYNTAX: INSERT INTO table [ (column [, column] ...) ] {VALUES (expr [, expr] ...) | subquery} To add rows to a single table. Use Append action query to get this
UPDATE command
PURPOSE: To change existing values in a single table. Use Update action query to get this SQL. SYNTAX: UPDATE table SET { (column [, column] ...) = (subquery) | column = { expr | (subquery) } } [, { (column [, column] ...) = (subquery) | column = { expr | (subquery) } } ] ... [WHERE condition]
A-2
Appendix B
Data dictionary
The data dictionary is used to find out what tables and so on have been created. The data dictionary is populated automatically and cannot be updated by the user. Access does not provide a proper data dictionary. If Access Options is selected from the Office button(choose Current database, then Navigation options and Show system objects) and system objects is set to yes, then several extra tables are listed whose names start with MSys, for example MSysObjects, and these can be examined. Database Tools/Database Documenter is also very useful.
B-1