SQL (Part 1)

advertisement
SQL (Part 1)
SQL (Structured Query Language) is the database query language that is used by Access. It was developed by IBM,
and the current standard is SQL92. However, Access does not adhere completely to the standard, and in fact adds some
features of its own. For the most part it’s not necessary for the Access developer/user to know SQL in depth, because
Access creates SQL automatically when you use the query design window to create a query. However, you can view
the code in the SQL view window and type standard SQL statements yourself if you wish.
SQL becomes more immediately relevant in two ways:
some types of queries cannot be created in query design view, notably subqueries and union queries
SQL can be embedded in VBA code
DML (Data Manipulation Language)
At its simplest, DML is basic querying. Essentially, the result of a query is itself a table (even if the query result is a
single cell you can think of it as a table with one row and one column).
To write an SQL query:
- start a new query in Design view
- close the Show Table window without adding a table.
The view button will show SQL. If you click it you will see SELECT; the word SELECT begins the statement and the
semicolon ends it – write your query in between. By convention SQL words are capitalized, but they do not have to be.
The general form of a statement is:
SELECT Column(s) FROM TableName
[WHERE Clause]
[GROUP BY clause]
[HAVING clause]
[ORDER BY clause];
The basic query is a Select query, and the simplest statement is as follows:
SELECT *
FROM Employees;
The * stands for all columns. There must be a FROM clause,
which refers to the table(s) being queried.
One semicolon (;) ends the statement
Essentially an SQL statement is a single statement, so line breaks are irrelevant to the logic of the query; however you
should use them to make the statement clear to read.
The view the result of the query, go to Datasheet view; the result is all columns and all records in the employee table;
to modify the query return to SQL
SELECT FirstName, LastName, Dept
FROM Employees;
Specify fields explicitly to restrict the number of columns in
the result. A comma separates the field names.
Order By clause
SELECT FirstName, LastName, Dept
FROM Employees
ORDER BY LastName;
You can use an ORDER BY clause to order the results. The
default is ASC, (for ascending), so can be left out. Use
ORDER BY field DESC if you want a descending sort.
SELECT FirstName, LastName, Dept
FROM Employees
ORDER BY Dept, LastName;
You can ORDER BY more than one column; the first-named
takes priority
The Where Clause
SELECT FirstName, LastName, Dept
FROM Employees
WHERE Dept = "MK"
The WHERE clause is used to restrict the records returned to
those that comply with one or more criteria.
1
ORDER BY LastName;
SELECT FirstName,LastName,Dept, PayRate
FROM Employees
WHERE Dept="MK" AND PayRate>=15
ORDER BY PayRate;
You can use comparison operators together with the
WHERE clause
SELECT FirstName, LastName, Dept, PayRate
FROM Employees
WHERE Dept="MK" AND PayRate>=15 AND
PayRate<=25
ORDER BY PayRate DESC;
You can specify multiple AND conditions when querying
data.
SELECT FirstName, LastName, Dept, PayRate
FROM Employees
WHERE Dept="MK"
AND PayRate BETWEEN 15 AND 25
ORDER BY PayRate DESC;
SQL provides a BETWEEN operator; it is more efficient
than using comparison operators, so the query should run
more quickly.
SELECT FirstName, LastName, Dept, PayRate
FROM Employees
WHERE Dept="MK" OR Dept = "CE"
ORDER BY Dept, PayRate DESC;
This example uses an OR condition
SELECT FirstName, LastName, Dept, PayRate
FROM Employees
WHERE (Dept= "MK" OR Dept = "CE")
AND PayRate BETWEEN 15 AND 25
ORDER BY Dept, PayRate DESC;
Brackets must be used to establish priority; without brackets
this example the AND condition would only apply to records
with CE in the Dept field (AND is evaluated before OR)
Arithmetic Expressions
Arithmetic operators are the same as in VBA (including Mod, Integer Division and Exponentiation)
SELECT FirstName, LastName, Dept, Hours * PayRate
FROM Employees
WHERE Dept="MK"
ORDER BY LastName;
Aliases
An alias is a column heading (caption). The SQL key word AS is used.
SELECT FirstName,
LastName, Dept, Hours * PayRate AS GrossPay
FROM Employees
WHERE Dept="MK"
ORDER BY LastName;
Concatenation operator
Use concatenation to ‘glue together’ fields, expressions or literals.
SELECT FirstName & " " & LastName AS FullName,
The concatenation operator is &
Dept, Hours*PayRate AS GrossPay
Two are used here; the first is to concatenate the space, the
FROM Employees
second to concatenate the LastName field
WHERE Employees.Dept="MK"
ORDER BY LastName;
Like Operator
The Like operator is used when you use a wild card in a query
SELECT FirstName & " " & LastName AS FullName,
Dept, Hours*PayRate AS GrossPay
FROM Employees
WHERE LastName LIKE "B*"
ORDER BY LastName;
2
NULL Operator
Null means there is no value in the field, the value is unknown
SELECT FirstName & " " & LastName AS FullName,
Dept, Hours*PayRate AS GrossPay
FROM Employees
WHERE Dept Is Null
ORDER BY LastName;
IN Operator
IN can be used to specify that the value of a field is in a set of values.
SELECT FirstName, LastName, Dept, PayRate
FROM Employees
WHERE Dept IN(“MK”, “CE”, “EE”)
ORDER BY Dept, PayRate DESC;
NOT Operator
Not is used to reverse the logic of a query.
SELECT LastName, Dept
FROM Employees
WHERE Not (Dept="MK" Or Dept="CE");
SELECT FirstName, LastName, Dept
FROM Employees
WHERE LastName NOT LIKE "B*"
ORDER BY LastName;
SELECT FirstName, LastName, Dept, PayRate
FROM Employees
WHERE Dept NOT IN(“MK”, “CE”, “EE”)
ORDER BY Dept;
SELECT FirstName, LastName, Dept, Hired
FROM Employees
WHERE Hired NOT BETWEEN #1/1/2002# AND
#1/1/2003#
ORDER BY Hired DESC;
Note that dates must be enclosed within # symbols and are
in North American format mm/dd/yy
Number Functions
Round() is used to round numbers. Int() is used to discard the decimal part.
SELECT LastName, Round(PayRate*1.1) As
If Round() is supplied one argument then it returns an
IncreasedPayRate
integer
FROM Employees;
SELECT LastName, Round(PayRate*1.1,2) As
IncreasedPayRate
FROM Employees;
The second optional argument to Round() is the required
number of decimal places.
SELECT LastName, Int(PayRate*1.1) As
IncreasedPayRate
FROM Employees;
There are no Trunc, Ceil, Floor, Power or Sqrt functions in Access SQL
3
Comparison Operators Reference
Operator
=
>
Meaning
Equal to
Greater than
<
<>
>=
<=
IN
LIKE
Less than
Not equal to
Greater than or Equal to
Less than or Equal to
Equal to a value within a collection of values
Similar to
BETWEEN
…AND
IS NULL
Within a range of values including the two values
which define the limits
Field does not contain a value
Notes
e.g., >15
all records with a value greater than 15
>M all values beginning with M through to the end of the
alphabet
e.g, IN(“Redhill”,”Epsom”,”Egham”)
e.g, LIKE “Sp*” finds Spanner and Sprockett; uses
wildcards
e.g, BETWEEN #1/1/96# AND #1/1/97#
Logical Operators Reference
Operator
AND
OR
NOT
Meaning
Both expressions must be true in order for the
entire expression to be judged true
If either or both expressions are true the entire
expression is judged to be true
Inverts Truth
Notes
AND is evaluated before OR
AND is evaluated before OR
e.g, NOT IN(“Redhil”l,”Epsom”,”Egham”)
Wildcards
You use wildcards with the Like operator to select data
Wildcard
Symbol
*
Meaning
Any number of characters
Notes
Like “M* “
all values beginning with M followed by none,
one or more characters
Like “ 08/*/92“
any day in August 1992; the zero in the month
part of the date is necessary
?
Any one character
Like “M??”
all values beginning with M and exactly two
additional characters
The key word DISTINCT
You can use the word DISTINCT to restrict the resulting recordset to unique values. For example the following query
will return 12 rows (because there are 12 records in the CompanyCars table.
SELECT Make, Model
FROM CompanyCars;
But if you inspect the resulting recordset, you will see there are duplicates. There are several Ford Mondeos for
example. If you want just unique values add the word DISTINCT to the statement as follows.
SELECT DISTINCT Make, Model
FROM CompanyCars;
4
There are now 7 records, each combination of Make and Model appears just once. There is no longer a one-to-one
mapping of the query result to records in the table. (In interactive query design view this is accomplished by going to
Query properties and setting the Unique Values property to Yes).
Totals Queries
When you use the Totals button in query design view you are able to group records on one or more fields and use one
of the inbuilt SQL functions like Avg.
SELECT Count(SalesOrders.OrderNo) AS CountOfOrderNo
FROM SalesOrders;
or alternatively,
SELECT Count(*) AS CountOfOrderNo
FROM SalesOrders;
Count (*) to count all records in recordset
SELECT Dept, Avg(PayRate) AS AvgOfPayRate
FROM Employees
GROUP BY Dept;
SELECT Dept, Count(*) AS EmployeeCount
FROM Employees
GROUP BY Dept;
SELECT Dept, Sum(Hours*Payrate) AS [Gross Pay]
FROM Employees
GROUP BY Dept;
SELECT Dept, Min(PayRate) AS MinOfPayRate
FROM Employees
GROUP BY Dept;
SELECT Dept, Avg(PayRate) AS AvgOfPayRate
FROM Employees
WHERE Hired >=#1/1/2003#
GROUP BY Dept;
You can also use Where clause
5
SQL (part 2)
Action Queries
queries select data from your tables, but have no effect on that data. Action queries make permanent changes to
the data in your tables. There are four types of Action query: Update, Append, Delete, MakeTable. To run an Action
query from interactive Access you must use the Run button.
Select
Update query
You can use an Update query when you want to change the value of data in your tables. The example effects a 5%
increase in the PayRate field of the Employees table where the value in the Dept field is MK.
UPDATE Employees
SET Employees.PayRate = [PayRate]*1.05
WHERE Employees.Dept ="MK" ;
Append query
An Append query can take some data or complete rows from one table and move them to another. For example, you
could transfer one month’s orders to another table at the end of each month. The tables involved must have at least one
field in common. The example shows how to transfer all the data in the CustomerID field in the Customers table to the
newly created (week 8 handout) Credit table.
INSERT INTO Credit (CustID)
SELECT Customers.CustomerID
FROM Customers ;
Delete query
queries can delete entire rows from a table, usually according to one or more criteria. They are very useful where
you have to delete thousands of records. Here is a simple example that deletes all rows from the equipment table where
the value in the DeptCode field is MK.
Delete
DELETE Equipment.*
FROM Equipment
WHERE Equipment.DeptCode = "MK" ;
MakeTable query
queries enable you to make a table from one or more existing tables. You may want to make a table in order
to create a snapshot of your data at a particular moment in time, or you could make a table with columns from other
tables in order to run queries against it (thereby improving performance). Another use would be if you needed to create
a temporary table as part of wider process. Note that you would not usually expect the resulting table of a MakeTable
query to be used for data entry.
MakeTable
Here’s an example which is useful – it would make a table called AnalysisOfSales against which you could run queries
and create charts. Inevitably it involves multiple Join clauses, so you are better off creating the query in design view.
6
The code created by Access is reproduced, with the relevant key words highlighted.
SELECT PurchaseItem.Quantity, Products.ProductID, Products.ProductName, Products.UnitPrice,
Customers.CustomerID, Customers.City INTO AnalysisOfSales
FROM (Customers INNER JOIN SalesOrders ON Customers.CustomerID = SalesOrders.CustomerID)
INNER JOIN (Products INNER JOIN PurchaseItem ON Products.ProductID = PurchaseItem.ProductID) ON
SalesOrders.OrderNo = PurchaseItem.OrderNo;
Remaining DML topics
Parameter query
Parameters allow the user to supply data to query criteria when the query is run; the parameter is enclosed in square
brackets, and user input replaces it and completes the WHERE clause.
SELECT *
FROM Products
WHERE UnitPrice > [Enter minimum cost] ;
The HAVING clause
The HAVING clause can be quite tricky to understand at first. It used in queries where GROUP BY is used, rather like
the WHERE clause, but the difference is that the HAVING applies to groups and WHERE applies to rows.
To illustrate the difference the following SQL statement uses WHERE to get the department and average pay rate
where the Dept field begins with M.
SELECT Dept, Avg(PayRate) AS AvgOfPayRate
FROM Employees
WHERE Dept Like "M*"
GROUP BY Dept ;
This statement gets the department and average pay rate of departments ‘having’ more than 3 rows (i.e. more than 3
employees).
SELECT Dept, Avg(PayRate) AS AvgOfPayRate
FROM Employees
GROUP BY Dept
HAVING Count(*) >3 ;
Using WHERE COUNT(*) > 3 is wrong
The next example lists departments and average pay rates of departments with an average pay rate of more than 20.
SELECT Dept, Avg(PayRate) AS AvgOfPayRate
FROM Employees
GROUP BY Dept
HAVING Avg(PayRate)>20 ;
Subqueries
A subquery is a select statement that is nested in the WHERE or HAVING clause of another select statement. For
example you may want the names of all employees who earn the lowest pay rate in the company.
Think of the problem as having two steps:
1. find the lowest pay rate:
SELECT MIN(PayRate) FROM Employees;
which yields 6.00
2. then list the employees whose pay rate = 6
SELECT FirstName, LastName, Dept, PayRate
FROM Employees
WHERE PayRate = 6;
You can combine the two statements if you use a subquery
7
SELECT FirstName, LastName, Dept, PayRate
FROM Employees
WHERE PayRate = (SELECT MIN(PayRate) FROM Employees);
The inner statement is processed first, then the outer one.
Another example: find all employees in the same department as WILSON
SELECT FirstName, LastName, Dept
FROM Employees
WHERE Dept =(SELECT Dept FROM Employees
WHERE LastName = 'Wilson');
Note there can only be one LastName of Wilson in the table.
This is how a subquery looks in interactive query design view
In Design view you
can create a subquery by typing the
inner SQL statement
into the Criteria cell
Subqueries can make use of the IN and EXISTS operators:
IN is used if you want to look up the value in a column of a table or another query.
The following statement returns records where there is a customer in a city where there isn’t an employee in that city.
SELECT CustomerID, City
FROM Customers
WHERE City NOT IN
(SELECT City FROM EmployeeAddresses) ;
If using IN the subquery can only return one column.
EXISTS is used to check whether an item exists in the subquery.
The following statement returns all values of CustomerID who have never placed a Sales Order
SELECT CustomerID
FROM Customers
WHERE NOT EXISTS
(SELECT * FROM SalesOrders
WHERE SalesOrders.CustomerID = Customers.CustomerID) ;
The inner SQL statement could be extended with a WHERE clause, for example since a certain date.
SELECT CustomerID
FROM Customers
WHERE NOT EXISTS
(SELECT * FROM SalesOrders
WHERE SalesOrders.CustomerID = Customers.CustomerID
AND SalesOrders.OrderDate >= Date()-90) ;
8
SQL (part 3)
This part continues the look at the DML component of SQL, specifically queries that are based on more than one table.
Querying more than one table
When more than one table is being queried, there is usually a join. Most of the time the join is supplied automatically,
and doesn’t present a problem. To simplify:

A join is supplied automatically in the query if there is a relationship between the tables.

By default the join is an Inner Join.
Inner Join
The Inner Join is the most common join employed in general use; it returns a recordset where there is value in one table
that matches a value in the other table on the join field.
To illustrate, observe the query design below.
Note the tables are in a one-to-many relationship, and the fields on which the tables are related are Deptcode and Dept.
This is the field the two tables have in common. The Deptcode field is the key field in the Departments table, but Dept
is not the key field in the Employees table (ID is). Note that neither of the key fields needs to appear in the query. The
query is asking for a list of employees’ last names and the name of the department they are in.
This query design produces the
recordset of 38 records, shown on the
right.
The SQL for the illustrated query uses an Inner Join:
SELECT LastName, Deptname
FROM Departments
INNER JOIN Employees ON Departments.Deptcode = Employees.Dept
ORDER BY LastName;
In a join clause specify the table name before
the column name using a dot. This is mandatory.
In the file Company2004.mdb there are 39 employees in the Employees table, but only 38 are in the query result. This is
because one of the employees does not have a value in the Dept field, i.e. isn’t assigned to a department. The effect of
the Inner Join is that the query returns records where the value in the Deptcode field in the Departments table matches the
value of the Dept field in the Employees table (assuming no other criteria, for simplicity’s sake). Therefore the record
with the Null value in the Dept field is not included.
Outer Joins
The characteristic of an Outer Join is that it returns the complete set of records from one table or other.
There are two types of Outer Join; Left Join and Right Join.
SELECT LastName, DeptName
FROM Departments
RIGHT JOIN Employees ON Departments.Deptcode = Employees.Dept
ORDER BY LastName;
9
This is how a Right Join appears in Design view. An
arrow points from the Employees field list to the field
list of the Departments table. The result of the query
includes all employees.
The Left Join reverses the logic it includes all departments, whether or not they have employees. As there are no
departments without employees in Company2004.mdb the Left Join produces the same result as the Inner Join.
SELECT LastName, DeptName
FROM Departments
LEFT JOIN Employees ON Departments.Deptcode = Employees.Dept
ORDER BY LastName;
Try the following SQL statements. There are 12 records in the CompanyCars table, 39 in the Employees table.
SELECT FirstName, LastName, RegNo, Make, Model
FROM Employees
INNER JOIN CompanyCars ON Employees.ID = CompanyCars.EmpID ;
SELECT FirstName, LastName, RegNo, Make, Model
FROM Employees
RIGHT JOIN CompanyCars ON Employees.ID = CompanyCars.EmpID ;
SELECT FirstName, LastName, RegNo, Make, Model
FROM Employees
LEFT JOIN CompanyCars ON Employees.ID = CompanyCars.EmpID ;
The Inner Join produces 9 rows in
the result – this implies 3 cars are not
allocated to an employee.
The Right Join produces 12 rows in
the result – all the records in
CompanyCars are included.
The Left Join produces 39 records in
the result – all the employees, but
only 9 of the cars.
Now do the equivalent of deleting the Join. Create the following statement:
SELECT FirstName, LastName, RegNo, Make, Model
FROM Employees, CompanyCars ;
If there is no join between the tables
you get 12 x 39 = 468 rows. The
result is meaningless.
This might lead to the question “is there a query that shows all the employees and all the cars in the same table?”
The answer is yes, it’s called a Union query. But first we’ll look at a basic example.
The Union query
A Union query can combine the sets of records from two tables in one query result. As a starting point recreate the
statement with the Left Join from above.
Union queries can be used where there is no way to join two tables. The next example shows a list of the values of the
City fields from the Employee Addresses table and the Customers table.
SELECT EmployeeAddresses.City
FROM EmployeeAddresses
UNION
SELECT Customers.City
FROM Customers ;
None of the values are duplicated
in the query result.
Save this query as Cities.
Try the following variation, no need to save the changes.
10
SELECT EmployeeAddresses.City
FROM EmployeeAddresses
UNION ALL
SELECT Customers.City
FROM Customers ;
In this variation the addition of the
SQL key word ALL results in a
result of 41 rows; there are 30
rows in EmployeeAddresses and
11 in Customers.
A more complex union query can view all the cars and all the employees:
SELECT FirstName, LastName, RegNo, Make, Model
FROM Employees
LEFT JOIN CompanyCars ON Employees.ID = CompanyCars.EmpID
UNION
SELECT FirstName, LastName, RegNo, Make, Model
FROM Employees
RIGHT JOIN CompanyCars ON Employees.ID = CompanyCars.EmpID ;
The result of this query has 42
rows: 39 employees plus 3 cars
that are not allocated to an
employee.
11
Download