SQL. Microsoft Access
Below you will find brief information for Access. This document provides guidance on various techniques and tools related to Microsoft Access. Learn how to manage data effectively, design forms and reports, and make your Access application more secure and user-friendly.
Advertisement
Advertisement
Microsoft Access Techniques
SQL
Access 2000 SQL conforms closely, but not completely, to the most recent ANSI standard for SQL,
SQL‐92.
The original SQL standard was completed as a USA ANSI (American National Standards
Institute) standard in 1986, and adopted as an ISO (International Standards Organization) standard in 1987. Expansions and revisions were released in 1989 and 1992. Because of ANSI and
ISO copyright restrictions, copies of the SQL standards specifications are available only for purchase.
The ANSI SQL‐92 standard specification can be found at
http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
I generally refer to IBM’s DB2 SQL Reference. It is available as PDF files on IBM’s website.
IBM DB2 Universal Database SQL Reference Volume 1 Version 8.2 SC09‐4844‐01 is available at ftp://ftp.software.ibm.com/ps/products/db2/info/vr82/pdf/en_US/db2s1e81.pdf
Version 9, DB2 for Linux, Unix, and Windows, is SC10‐4250‐00 and is available at ftp://ftp.software.ibm.com/ps/products/db2/info/vr9/pdf/letter/en_US/db2s2e90.pdf
SELECT
General format of SELECT query is:
SELECT … FROM … WHERE … GROUP BY … HAVING … ORDER BY …
The clauses of the select statement are processed in the following sequence:
1. FROM phrase
2. WHERE phrase
3. GROUP BY phrase
4. HAVING phrase
5. SELECT phrase
Thus you cannot filter data using a field created with AS in the SELECT phrase:
SELECT x, y, z AS mm FROM g WHERE mm = “w” is invalid. This can be effected with a subselect:
SELECT x, y, mm FROM (SELECT x, y, z AS mm FROM g) WHERE mm = ‘w”
NOTE: In Access 2003 a subselect is valid in a FROM phrase.
The SELECT phrase is composed of a list of one or more field names separated by commas:
SELECT Hostname
SELECT Hostname, Facility
In the SELECT phrase you can rename a field in the result set by the use of the AS clause:
SELECT Hostname, Facility AS Fc
SELECT Facility, Count(*) AS CountFacility
This is strictly not an alias name; in DB2 an alias is an independent object defined with DDL.
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 100 of 119
Microsoft Access Techniques
The following example illustrates the use of the Format function in a SELECT phrase and the AS label with an embedded space.
SELECT Format(CandidateFiles.MigrateDate,”Short Date”) AS [Migrate Date],
LibraryName, Count(*) AS [Count]
FROM CandidateFiles
WHERE (((IsNull([MigrateDate]))=False))
GROUP BY Format(CandidateFiles.MigrateDate,”Short Date”),
CandidateFiles.LibraryName
ORDER BY 1, 2;
When a SELECT sources a table with a field with type Hyperlink, the query datasheet also has the Hyperlink. Unless . . . the query includes a UNION. If this is undesirable, you can get around it by using two queries:
SELECT ID, URL FROM MigrateWorksheet WHERE ID IN (SELECT ID FROM
ErrorQueryWithUnion)
ORDER BY field | field position ASC | DESC [, field | field position ASC | DESC ]
Examples:
ORDER BY 1, 2
ORDER BY field2, field5 DESC, field6
SELECT INTO
This query is a make‐table query, i.e., it inserts records into a previously non‐existent table. When you create the table, the fields in the new table inherit the data type and field size of each field in the queryʹs underlying tables, but no other field or table properties are transferred (such as primary key). Syntax:
SELECT field1[, field2[, ...]] INTO newtable [IN externaldatabase] FROM source
The following example copies the named fields in every record:
SELECT Column1, Column2, Column3,
INTO Table2
FROM Table1
The following example copies all the fields in every record:
SELECT *
INTO Customers_copy
FROM Customers
I cannot find a way to create a field that did not exist in the source table.
JOIN
The JOIN phrase is used to combine tables. It works best when used with tables in a parent‐ child relationship. When used with other relationships, the result set may be a fiction. It can contain all the possible combinations of the two (or more) tables—which is probably not what you want.
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 101 of 119
Microsoft Access Techniques
When using Design View to create queries with JOINs with foreign keys, show the tables in reverse order of their significance. For instance if the the primary table is A and the lookup table is B, order them as B then A (B to the left of A). This gets the JOINs written correctly.
In any case, use SQL View to verify which join(s) were created; change by overtyping as necessary.
JOINs are sometimes used to qualify the selection. When the table relationship is not parent‐child, this may be better accomplished with a WHERE phrase and a subquery.
There are 3 different JOINS.
INNER JOIN returns data when the join condition is true (2 tables match on 1+ common fields).
LEFT JOIN returns data for all records in the left table even if there are no matching records in the right table.
RIGHT JOIN returns data for all records in the right table even if there are no matching records in the left table.
When using a join for a foreign key‐lookup table, use the join (left/right) that handles the case where there is no matching record.
Nested joins are done differently than in DB2. In first example, join two tables where they will always match on a common field (as in parent‐child or lookup table when foreign key is required). In second example, join one table to two tables. When second table is joined on foreign key and key is required, use inner join. When second table is joined on foreign key and key is optional, use left join. ?? Third example is of main table with two foreign keys, one required, the other optional; FROM clause right joins tableC to inner join of tableA and
B.
SELECT * FROM tableA INNER JOIN tableB ON tableA.fieldA = tableB.fieldA
SELECT * FROM (tableA INNER JOIN (tableB INNER JOIN tableC ON tableB.fieldB = tableC.fieldB) ON tableA.fieldA = tableB.fieldA)
SELECT * FROM (tableC RIGHT JOIN (tableA INNER JOIN tableB ON tableA.fieldA = tableB.fieldA) ON tableC.fieldB = tableA.fieldB)
Access will do a sequence of two left joins, but not an inner join followed by a left join.
Example of JOIN on more than one field:
SELECT fields
FROM table1 INNER JOIN table2
ON table1.field1 = table2.field1 AND
ON table1.field2 = table2.field2) OR
ON table1.field3 = table2.field3)];
UNION
A UNION query combines two or more result tables or queries. Syntax:
| TABLE tablename | UNION | TABLE tablename | UNION . . . | ORDER BY
| queryname | UNION ALL | queryname | UNION ALL . . .
| SELECT . . . | SELECT . . .
The UNION phrase causes duplicates to be excluded. The UNION ALL phrase causes duplicates
to be retained.
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 102 of 119
Microsoft Access Techniques
All queries must return the same number of fields, but they may have different data types and sizes.
Aliases may be used only in the first SELECT statement; they are ignored in all others.
The ORDER BY phrase can use column names or integers. If the former, they must reflect the field names used in the first SELECT statement.
SQL like “queryname1 UNION queryname2” fails the syntax check. “SELECT . . . FROM
queryname1 UNION SELECT . . . FROM queryname2” works.
UPDATE
General syntax of UPDATE query is:
UPDATE table SET newvalue WHERE criteria;
UPDATE table1 INNER/RIGHT JOIN table2 ON table1.id = table2.id
SET table1.fielda = newvalue;
Be aware that the second syntax is not compatible with other DBMS like SQL Server. Nor is their syntax compatible with Access.
[There is no FROM phrase as in other versions of SQL.)
Example:
UPDATE Orders
SET OrderAmount = OrderAmount * 1.1, Freight = Freight * 1.03
WHERE ShipCountry = 'UK';
The following example does a character replacement in a table, saves the field before it is changed, and saves a code to reflect the nature of the change. The error code is meant to hold several values, each indicating a separate update.
UPDATE Test
SET OriginalFilename = Filename, Error = Error & “&”, Filename =
REPLACE(Filename, “&”, ““)
WHERE InStr(Filename, “&”) > -0;
Apparently you cannot use a UNION with an UPDATE.
You can use an UPDATE with a JOIN but only when you are accessing tables (and not queries).
If the SQL is in an (Update) query then it must have property Unique Records = Yes., otherwise the query won’t work—it is “not updatable”.
(This works in Access and MySQL 5 but not in SQL Server)
UPDATE TableOne
INNER JOIN TableTwo ON TableOne.commonID = TableTwo.commonID
SET TableOne.field1 = TableTwo.fieldX
UPDATE TableOne, TableTwo
SET TableOne.field1 = TableTwo.fieldX
WHERE TableOne.commonID = TableTwo.commonID
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 103 of 119
Microsoft Access Techniques
UPDATE CandidateFiles AS CF
INNER JOIN MigrateWorksheet AS MW
On CF.ID = MW.ID
SET CF.LibraryName = MW.LibraryName, CF.Library = IIF(MW.LibraryName =
“Public”, “U”, “R”)
WHERE CF.ID IN (SELECT ID FROM MigrateDiscrepancyE);
When you JOIN two tables, if the source field of a SET statement is an autonumber field, then the
corresponding field in the destination table must be a long integer (and not an autonumber).
The following query updates records in one table that match records in a second table. In addition it appends a record to the first table when no record matches the second table row.
UPDATE Table1
RIGHT JOIN Table2
ON
Table1.Ix = Table2.Ix
SET
Table1.Ix = Table2.Ix,
Table1.Descr = Table2.Descr
I learned the hard way that I cannot have an UPDATE query with two fields and where field 2 is calculated from the value of field 1. Here is what I meant to say:
An expression may contain references to columns of the target table of the UPDATE statement.
For each row that is updated, the value of such a column in an expression is the value of the column in the row before the row is updated.
Here’s an example of nested joins in an update query. This query was written to handle the situation where data from one table (N) was being merged into a second table (S). The merge was effected by copying data (only when it was of higher quality) from the first table into matching records in the second table. Almost 1000 records needed to be updated. The merge was complicated by the quality of data in each table which resulted in over 10 use cases for handling the merge, many of which reflected specific data values. The approach was to create a temporary table to control the update, this temporary table was created with a SELECT INTO query with
GROUP BY:
SELECT INTO ScannedDiffModel
N.Model AS NM, S.Model AS SM, Count(*) AS RecordCount, "" AS UseCase
FROM Scanned AS N INNER JOIN Server AS S ON N.Hostname=S.Hostname
WHERE N.Model<>S.Model And N.Model<>""
GROUP BY N.Model, S.Model;
Then the use case identifier was entered manually in the new table. This table then was used to control the UPDATE. For use case C:
UPDATE
(ScannedDiffModel AS D INNER JOIN
(Server AS S INNER JOIN Scanned AS N
ON S.Hostname = N.Hostname)
ON S.Model = D.SM
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 104 of 119
Microsoft Access Techniques
AND N.Model = D.NM)
SET S.Model = N.Model
WHERE D.UseCase = "C";
INSERT
Used to append records to an existing table.
General format of INSERT query is:
INSERT INTO target [(field1[, field2[, …
SELECT [source.]field1[, field1[, …] multiple records
INSERT INTO target [(field1[, field2[, …
VALUES (value1[, value2[, …]])
INSERT INTO target [(field1[, field2[, …
VALUES (value1(, . . .]), (value2[, . . .])
INSERT INTO MigrateWorksheet
SELECT *
FROM FilesToMigrate; single record two records
The use of * to refer to fields works only when fields have the same name in source and destination.
There are two simple forms:
INSERT INTO . . . VALUES . . .
INSERT INTO . . . SELECT . . . FROM . . .
The second form can also contain WHERE, GROUP BY, and HAVING clauses, as well as table joins, aliases, and subselects.
INSERT INTO table1
SELECT *
FROM table2
WHERE fieldx NOT IN (SELECT fieldx from table1)
This form works fine except when the inserted records could duplicate existing records on the primary key. This can happen when there is an autonumber field in both tables.
DELETE
The DELETE query deletes one or more records from a table. The general syntax of the DELETE
query is:
DELETE FROM table WHERE criteria
Examples:
DELETE * FROM Employees WHERE Title = "Trainee"
DELETE * FROM Employees
TRANSFORM
The TRANSFORM statement creates a crosstab query, aka pivot table (in Excel); the statement is non‐standard and unique to Access. The result set in datasheet view looks like a two‐
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 105 of 119
Microsoft Access Techniques
dimensional table with a x‐axis, y‐axis, and some data in the intersecting cells. The result set is easily published by pasting it into a Word document.
TRANSFORM aggfunction selectstatement
PIVOT pivotfield [IN (value1[, value2[, ...]])]
The TRANSFORM statement has these parts:
Part Description
aggfunction An SQL aggregate function that operates on the selected data. The results populate the intersecting cells. selectstatement pivotfield
A SELECT statement. This selects the y‐axis values (row headings). This statement can include a WHERE clause and/or a GROUP BY clause.
The field or expression you want to use to create column headings in the queryʹs result set; the x‐axis. value1, value2 Fixed values used to create column headings. This will restrict pivotfield to create headings only for the specified values. Columns are created for all values even if there is no data.
SQL aggregate functions: Avg, Count, First, Last, Min, Max, Sum, StDev (standard deviation), and Var (variance).
Example:
TRANSFORM First(Definition)
SELECT Entity, Attribute FROM AttributesInDuplicateEntities
GROUP BY Entity, Attribute
PIVOT ModelName
Entity
CURRENT
STATUS
SERVICE
REASON
CURRENT
STATUS
SERVICE
REASON
DEBT
CrosstabAttributeDefinitionsByEntityModel
Attribute
ITEM CSD
STAGING
ITEM
MONEY
MARKET
FUND
STAGING
ITEM
MUTUAL
FUND
STAGING
ITEM SERVICE SDA
STAGING
issue status service change time
The time expressed in hours, minutes and seconds when a change in issue status and service was recorded. operational issue service code
A symbol identifies one and only one operational service.
AD_VALOREM_TAX_CD Ad Valorem Tax Status: B = supported b limited/unlimited ad valorem tax pledge L =
Supported by limited ad valorem tax pledge U = supported by unlimited ad valorem tax pledge Not applicable will be blank in this field.
DEBT bank qualified status code A code which identifies the
Bank Qualified status of an
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 106 of 119
Microsoft Access Techniques
Entity
DEBT
DEBT
DEBT
DEBT
DEBT
DEBT
CrosstabAttributeDefinitionsByEntityModel
Attribute
ITEM CSD
STAGING
ITEM
MONEY
MARKET
FUND
STAGING
ITEM
MUTUAL
FUND
STAGING
ITEM SERVICE SDA
STAGING
bearer suffix identifier bond form code
Issue.
A code which identifies the forms (registered, bearer, both) in which a bond may exist. call type code conversion status code convertible indicator convertible to cash amount
An indicator which identifies whether a
Debt Issue is or is not convertible. Y =
Debt Issue is convertible N = Debt
Issue is not convertible
A code which identifies the times in the year when the call may be exercised.
An indicator which identifies whether a Debt Issue is or is not convertible. Y = Debt Issue is convertible N = Debt Issue is not convertible
The dollar amount into which a
Debt Issue may be converted.
Correlation Names
Access can use correlation names for tables/queries in FROM phrase. One source says a table correlation name is aka alias. The syntax can be:
FROM tablea AS a
FROM tablea a
Example:
SELECT S.ID, S.URL, S.Title AS [Susan Title], S.Subject AS [Susan Subject],
S.[Sub-Subject] AS [Susan Sub-Subject], S.DocumentType AS [Susan
DocumentType],
L.Title AS [Larry Title], L.Subject AS [Larry Subject], L.[Sub-Subject] AS
[Larry Sub-Subject], L.DocumentType AS [Larry DocumentType]
FROM FilesToMigrateSusan AS S INNER JOIN FilesToMigrateLarry AS L
ON S.ID = L.ID
ORDER BY 1;
Example:
UPDATE CandidateFiles AS CF
INNER JOIN Library ON UCase(CF.Site) = Library.SiteID AND UCase(CF.Library) =
Library.LibraryID
SET CF.LibraryName = Library.LibraryName
WHERE (IsNull(CF.LibraryName) OR IsEmpty(CF.LibraryName)) AND UCase(CF.Migrate)
= “Y”;
Using Comparisons in SQL
Beware comparing dates. If the field is a Short Date, i.e., created by Format(field, “Short Date”), then the field is actually text and comparisons will yield erroneous results. If you want to compare two dates, be sure they are either date‐time data types or DateValue(date‐time field).
The DateValue function returns the Short Date as a date, not text.
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 107 of 119
Microsoft Access Techniques
Predicates
There are several types of predicates.
comparison, use comparison operators like > =
quantified: ANY, SOME, ALL, DISTINCT, DISTINCTROW, TOP n [PERCENT]
Use the ANY or SOME predicate, which are synonymous, to retrieve records in the main query that satisfy the comparison with any records retrieved in the subquery. The following example returns all products whose unit price is greater than that of any product sold at a discount of 25 percent or more:
SELECT * FROM Products
WHERE UnitPrice > ANY
SELECT UnitPrice FROM OrderDetails
WHERE Discount >= .25)
SELECT DISTINCT fielda, fieldb FROM tablex
between: BETWEEN, NOT BETWEEN
Examples:
EMPLOYEE.SALARY BETWEEN 20000 AND 40000
SALARY NOT BETWEEN 20000 + HV1 AND 40000
exists: EXISTS
The EXISTS predicate tests for the existence of certain rows.
The fullselect may specify any number of columns, and
The result is true only if the number of rows specified by the fullselect is
not zero.
The result is false only if the number of rows specified is zero
The result cannot be unknown.
Example:
EXISTS (SELECT * FROM TEMPL WHERE SALARY < 10000)
The EXISTS predicate specifies a correlated subquery (defined in section Subselect‐Subquery) and
then compares a value against the existence of one or more rows in that subquery, i.e., whether the subquery returns any records (1+ records is True, 0 records is False). “WHERE EXISTS subquery” is satisfied if subquery returns True; “WHERE NOT EXISTS subquery” is satisfied if subquery returns False.
Functionally it is similar to IN and NOT IN, but may be more efficient. In general, if the selective predicate is in the subquery, then use IN. If the selective predicate is in the parent query, then use
EXISTS [not sure what this means].
SELECT fieldlist FROM datasource WHERE [NOT] EXISTS (subquery)
Which customers have placed an order?
SELECT CustomerID, CompanyName
FROM Customers AS A
WHERE EXISTS
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 108 of 119
Microsoft Access Techniques
(SELECT * FROM Orders WHERE A.CustomerID = Orders.CustomerID)
Which customers have not placed an order?
SELECT CustomerID, CompanyName
FROM Customers AS A
WHERE NOT EXISTS
(SELECT * FROM Orders WHERE A.CustomerID = Orders.CustomerID)
in: IN, NOT IN subject of predicate can be an expression, fullselect, or set of expressions, for example: expression IN expression
is equivalent to a basic predicate of the form: expression = expression expression IN (fullselect)
is equivalent to a quantified predicate of the form: expression = ANY (fullselect) expression NOT IN (fullselect)
is equivalent to a quantified predicate of the form: expression <> ALL (fullselect) expression IN (expressiona, expressionb, ..., expressionk) is equivalent to: expression = ANY (fullselect) where fullselect in the values‐clause form is: VALUES (expressiona), (expressionb), ...,
(expressionk)
(expressiona, expressionb,..., expressionk) IN (fullselect) is equivalent to a quantified predicate of the form: (expressiona, expressionb,..., expressionk)
= ANY (fullselect)
Example:
SELECT ID, Filename, Migrate
FROM CandidateFileExtensions
WHERE Extension NOT IN (SELECT Extension FROM ValidFileTypes)
AND UCase(Migrate) = “Y”;
like: LIKE, NOT LIKE
The LIKE predicate searches for strings that have a certain pattern. The pattern contains text and special characters:
The underscore character (_) represents any single character.
The percent sign (%) represents a string of zero or more characters.
Any other character represents itself.
Example:
SELECT PROJNAME FROM PROJECT
WHERE PROJECT.PROJNAME LIKE '%SYSTEMS%'
null: NULL, NOT NULL
This predicate tests for null values.
Examples:
PHONENO IS NULL
SALARY IS NOT NULL
1 It is the WHERE x = y phrase that establishes the subquery as correlated.
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 109 of 119
Microsoft Access Techniques
SELECT Predicates
The SELECT statement can include predicates:
SELECT (ALL | DISTINCT | DISTINCTROW | TOP n [PERCENT]) FROM table . . .
ALL is assumed if none specified.
SELECT ALL * FROM table . . .
SELECT * FROM table . . . ‘ same as SELECT ALL * FROM . . .
DISTINCT omits records containing duplicate data in the selected fields. When more than one field is specified, it is their combination that is evaluated for unique values.
SELECT DISTINCT field FROM table
DISTINCTROW omits data based on entire duplicate records. Useful with inner joins, but only when fields from some (but not all) of the tables are selected.
SELECT DISTINCTROW field FROM table
TOP returns a given number of record that fall at the top/bottom of a range specified by an
ORDER BY phrase.
SELECT TOP 25 fieldA, fieldB FROM table ORDER BY Zip DESC
SELECT TOP n PERCENT fieldA, fieldB FROM table ORDER BY ID ASC
Create one row with a value of your own choosing.
SELECT TOP 1 “all” AS fieldname FROM table
Populate a list box with values from a table and a special value like “all.” To get “all” to sort first, put one blank in front (“ ALL”).
SELECT TOP 1 “ ALL” AS [Tier] FROM JobTitle
UNION
SELECT DISTINCT [Tier] from JobTitle
Subquery-Subselect
Access SQL is a subset of SQL‐92. Some capabilities are missing. Especially in the following list, it may be that Access disallows a subselect in a FROM phrase.
A subquery is a SELECT statement used as an expression (nested) within another query. It is always bracketed by parentheses.
There are two kinds of subqueries. A plain subquery is not dependent on the outer query; also known as an uncorrelated subquery. A correlated subquery is dependent on the outer query in that it contains a reference to one or more columns in the outer query. Within a subquery a reference to a column of a table identified at a higher level (e.g., an outer query) is called a correlated reference.
Subqueries can be nested, establishing an hierarchy. For example, query 1 uses query 2 which uses query 3. The terminology here is that queries 2 and 3 are inner queries, query 1 is an outer query for the other two, and query 2 is an outer query for query 3.
Cannot have an ORDER BY phrase.
Can refer to tables specified in a previous outer query within the hierarchy with a correlated reference:
SELECT * FROM tableA A1 WHERE fieldB IN (SELECT fieldB FROM tableB WHERE fieldC
= A1.fieldC)
Can be used in the field list (the AS clause works with DB2 but not perhaps Access):
SELECT fieldA, fieldB, (SELECT fieldC FROM . . .) AS xyz FROM . . .
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 110 of 119
Microsoft Access Techniques
Can be used in the FROM phrase:
SELECT ZZ.fieldA, ZZ.fieldB FROM (SELECT field A, field B, fieldC FROM . . .)
AS ZZ . . .
Can be used in a JOIN phrase:
SELECT fieldA, fieldB FROM tableA A1 JOIN (SELECT fieldB FROM . . .) AS YY ON
. . .
Can be used in a WHERE phrase with membership predicates (may not work):
SELECT * FROM tableA WHERE fieldB [NOT] IN (SELECT fieldB FROM . . .)
SELECT * FROM tableA WHERE (fieldA, fieldB) IN (SELECT field A, fieldB FROM . .
.)
SELECT * FROM tableA WHERE fieldB = ANY/SOME/ALL (SELECT fieldB FROM . . .)
SELECT * FROM tableA WHERE (fieldB, filedC) = ANY/SOME (SELECT fieldB, fieldC
FROM . . .)
Note: the “= ANY” predicate is the equivalent of the “IN” predicate when both are of the form
“(expressiona, expressionb, . . . , expressionk) IN (subquery).” Similarly, “NOT IN” is the equivalent of “<> ALL”.
Can be used in a WHERE phrase with comparison predicates:
SELECT * FROM tableA WHERE fieldB > (SELECT Avg(fieldB) FROM tableB . . .)
Other comparison operators: =, <, <>, >=, <=.
Can be used in a WHERE phrase with existence predicate:
SELECT * FROM tableA WHERE EXISTS (SELECT fieldB FROM . . .)
Can be used in a HAVING phrase:
SELECT * FROM tableA GROUP BY fieldA HAVING Max(fieldC) < (SELECT Avg(fieldC
FROM . . .)
When you join one table to another for purposes of qualifying the first table’s records, the subselect can be used in both the FROM phrase and the JOIN phrase with WHERE phrase to limit the number of records in the two temporary tables before they are joined. The following sample also uses the GROUP BY phrase instead of a SELECT DISTINCT.
SELECT . . . FROM (SELECT . . . FROM tableA WHERE . . . ) AS T1 JOIN (SELECT .
. . FROM tableB WHERE . . . GROUP BY . . .) AS T2 ON . . .
The correlated subquery will be run once for each candidate row selected by the outer query.
It is good practice to qualify all column references used in subqueries.
SELECT * FROM tableA WHERE ID IN (SELECT A FROM tableB WHERE tableB.x = tableA.x)
Miscellaneous Query Techniques
Enclose field names in square brackets when using functions in SQL.
SELECT ID, Len([Notes]) AS NotesLength FROM . . .
Use custom VBA functions for complex processing. If you want to set a table field equal to a calculated value whose calculation involves using complex string manipulation, conditional processing, and/or APIs, then create a custom function in a VBA module and invoke it in your SQL statement.
SELECT ID, CalcIP([Hostname]) AS CalcIP FROM . . .
Where CalcIP() is a VBA function:
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 111 of 119
Microsoft Access Techniques
Function CalcIP(h as String)
. . .
End Function
When you use VBA functions in a query, especially in a WHERE clause, you may get a runtime error (“invalid procedure call”). This happens when one or more records come to grief with the functions. For example, using an InStr() function without excluding the instances when the value is zero (meaning the substring could not be found) will cause an error.
When you want counts of groups of records where there is more than one field whose values can be combined as a group, do as follows:
SELECT A, B, C, D, Count(*) AS RecordCount
FROM tablea
GROUP BY A, B, C, D;
This will yield a recordset like the following:
A B C D RecordCount
Intel
Linux
Microsoft
Windows 2
1
Linux
Linux
Linux
IBM
Microsoft
Red Hat
AIX
Windows
Enterprise Linux
4
1
2
Unix
Unix
Unix
Unix
IBM
Red Hat
Sun Microsystems
Microsoft Windows
Microsoft Windows IBM
Microsoft Windows Microsoft
AIX
Enterprise Linux
Solaris
AIX
Windows NT
5
318
2
140
20
3
102
When you want to count records by groups of data and one of the groups is, not the domain of values of a field but whether a certain value is present or not, use the following form of
query:
SELECT Facility, Billed, Count(*) As RecordCount
FROM (SELECT Facility, IIf(InStr([InventoryMethod], "billed") = 0, "no", "yes")
AS Billed FROM Server)
GROUP BY Facility, Billed;
Facility Billed RecordCount no yes
319
803
BDC no
RCC no
RCC yes
2
209
252
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 112 of 119
Microsoft Access Techniques
Facility Billed RecordCount
SDC no 48
SDC yes 40
Select the record for each record key having the latest date. Only works if the date field is not defined as Short Date
SELECT JobID, Max(Date) AS LatestDate
FROM History
GROUP BY JobID
ORDER BY 1;
Select records having particular date.
SELECT BIRTHDAY_TABLE.PersonName, BIRTHDAY_TABLE.BirthDate
FROM BIRTHDAY_TABLE WHERE (Month(BIRTHDAY_TABLE.BirthDate)) < Month(Date())
OR ((Month(BIRTHDAY_TABLE.BirthDate)) = Month(Date()) AND
Day(BIRTHDAY_TABLE.BirthDate)< Day(Date())) ORDER BY
Month(BIRTHDAY_TABLE.BirthDate), Day(BIRTHDAY_TABLE.BirthDate);"
Select records with time‐date stamp = today
WHERE DateValue([tableA].[fieldA]) = Date()
Find combinations of fields that have the same value. In this example the table has many more fields than these. Note that the WHERE phrase excludes some records from consideration. The HAVING phrase selects only instances where there are duplicates (more than one occurrence in the group).
SELECT SiteTitle, LibraryName, Title, Count(Title) AS CntTitle
FROM MW
WHERE DoNotMigrate = False
GROUP BY SiteTitle, LibraryName, Title
HAVING Count(Title) > 1
ORDER BY 1;
Select records having a particular date.
SELECT ID, StartDate
FROM Claim
WHERE
StartDate=#09/06/2009#
ORDER BY 1;
List the records associated with duplicate key values (i.e., that are duplicates on one or more fields). To extend the previous example, select the individual records that match the combination of fields selected in that query.
SELECT *
FROM MW INNER JOIN (query above) AS D
ON MW.SiteTitle = D.SiteTitle AND MW.LibraryName = D.LibraryName AND MW.Title =
D.Title ;
List the records that are duplicates on one field.
SELECT SiteTitle, LibraryName, Title, ID
FROM MW
WHERE Title IN
(SELECT Title FROM MW
GROUP BY Title
HAVING Count(Title) > 1)
ORDER BY 3;
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 113 of 119
Microsoft Access Techniques
Create new field with conditional value
SELECT RC.[RS CD], RC.EFFDT, RC.[RC SEQ], RC.[ERR IF NO VAL SW], RC.[BF CD],
BF.[CHAR TYPE CD], BF.[CHAR SRC FLG], BF.[ERR IF NO VAL SW],
IIf([RC].[ERR IF NO VAL SW]="Y" Or [BF].[ERR IF NO VAL SW]="Y","Y","") AS
Required
FROM RC INNER JOIN BF ON RC.[BF CD] = BF.[BF CD]
WHERE (((BF.[CHAR TYPE CD])<>"N/A") AND ((BF.[CHAR SRC FLG])<>"CH"))
ORDER BY RC.[RS CD], RC.[BF CD];
Get all unique combinations of month and year from a date in a table
SELECT DISTINCT Year([Complete Date]) & "-" & Month([Complete Date]) AS YM
FROM [MT Log Table]
ORDER BY 1;
Count records returned by query
SELECT Count(*) AS CountA1
FROM [A1 Detail List];
Count records returned by query and new column created to hold query name
SELECT
"A1 Detail List" AS [Query Name],
Count(*) AS Count
FROM [A1 Detail List];
Count groups of records. For example, for each record in tableA, count the number of records in tableB with a foreign key of the tableA record. The basic approach is to combine the GROUP BY clause and the Count function, each focused on a different field. If you need to add another table, do this as a separate query that is based on the count query. In the second example, tableB is DocumentSubject. NOTE: If you use Count(*) on an inner join, it will return 1 when there are no matching records; the solution is to say
Count([tablename].[fieldname])
SELECT Count(*) AS [Bill Factor Count], [Bill Factors by Rate Category].[Rate
Category]
FROM [Bill Factors by Rate Category]
GROUP BY [Bill Factors by Rate Category].[Rate Category];
SELECT SubjectsWithPath.ID, Count(DocumentSubject.SubjectID) AS DocCount
FROM SubjectsWithPath LEFT JOIN DocumentSubject ON SubjectsWithPath.ID =
DocumentSubject.SubjectID
GROUP BY SubjectsWithPath.ID;
Add numbers in records
SELECT PortalName, Sum([Count]) AS CountChanges
FROM JoinCountsAfterExportGrouped
GROUP BY PortalName;
CASE construct for creating new output field based on multiple conditions
…
Switch([Alg Type].[ALG TYPE CD]="CV",[SQ Rule].[SQ PARAM 01],[Alg Type].[ALG
TYPE CD]="BC" Or "CD" Or "MD",[SQ Rule].[SQ PARAM 03],[Alg Type].[ALG TYPE
CD]="MA",[SQ Rule].[SQ PARAM 08]) AS Parameter,
… simpler version:
Switch([Alg Type Parm].SEQNO=1,[SQ Rule].[SQ PARAM 01],[Alg Type
Parm].SEQNO=3,[SQ Rule].[SQ PARAM 03],[Alg Type Parm].SEQNO=8,[SQ Rule].[SQ
PARAM 08]) AS Parameter,
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 114 of 119
Microsoft Access Techniques
Create a table while putting data into it
SELECT * INTO newtable FROM (subquery)
SELECT field[, field2. . . ] INTO newtable FROM table
SELECT field[, field2. . . ] INTO newtable FROM queryname
Create named table by the insertion of the results of a named query
SELECT * INTO Counts FROM [A1 Detail Count]
Create named table by inserting some rows from a named query
SELECT * INTO TempSelection
FROM AssignedExceptions
WHERE [Exception ID] = 6409;
Create named table by inserting aggregate rows from a named query
SELECT [Batch Job Name] AS Job, [Run Date-Time] AS [Date], [Message Category]
AS [Msg Cat], [Message Number] AS [Msg Nbr], [Assigned To], Count([Exception
ID]) AS Count INTO Test
FROM AssignedExceptions
GROUP BY [Run Date-Time], [Batch Job Name], [Message Category], [Message
Number], [Assigned To]
ORDER BY [Run Date-Time], [Batch Job Name], [Message Category], [Message
Number], [Assigned To];
Empty named table
DELETE * FROM tablename
Delete named table
DROP TABLE tablename
Append query result to a named table; clearly, the field names in the Counts table are the same as in the query
INSERT INTO Counts SELECT * FROM [A1 Detail Count]
INSERT INTO tablename (field1, field2 . . .) VALUES (value1, value2 . . .) example:
INSERT INTO Song (Title, Composer) VALUES ("White Christmas", "Irving Berlin")
INSERT INTO tablea (fielda1, fielda2, . . .) SELECT fieldb1, fieldb2, . . .
FROM tableb 'when field names/sequence differ
Add records to named table and set value of one field based on values of other fields.
INSERT INTO StatusByPhase ( Department, JobTitle, Phase )
SELECT [Department], [JobTitle],
Switch
(IsDate([DateKNCompleted]),5,(IsDate([DateJobProfileDrafted]) And
IsDate([DateInventoryDrafted])),4,IsDate([DateLastTranscriptSent]),3,IsDate([Da teJobOutlineDrafted]),2,IsNull([DateJobOutlineDrafted]),1) AS Phase
FROM JobTitle;
Convert a table—using only three columns—into a two‐dimensional matrix. The x‐axis is
CHAR TYPE CD, the y‐axis is RS CD. CHAR SCR FLG is in the intersections. Additional columns are ignored.
TRANSFORM First([Matrix List].[CHAR SRC FLG]) AS [The Value]
SELECT [Matrix List].[RS CD]
FROM [Matrix List]
GROUP BY [Matrix List].[RS CD]
PIVOT [Matrix List].[CHAR TYPE CD];
Set date field
UPDATE Message
SET Message.[Revision Date-Time] = Date() or Now() for date-time
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 115 of 119
Microsoft Access Techniques
WHERE . . . ;
An update query can update more than one field at a time:
SET fieldA = "y", fieldB = "x", . . .
Update query with inner join must have property Unique Records = Yes. If not, the query won’t work—it is “not updatable”.
Delete record from table
DELETE [table.*] FROM table WHERE criteria
DELETE * FROM Employees WHERE Title = 'Trainee'
DELETE ID FROM Subject WHERE ID = 7 strSQL = "DELETE ID FROM Subject WHERE ID = " & sid (DoCmd.RunSQL strSQL)
Import Excel file with long text fields
Access 97 will not create Memo text fields when importing an Excel file. Instead, the fields are imported as Text fields and truncated to 255 characters. (Apparently not so in Access 2000.)
The solution:
1. In Excel, save the file as a CSV (comma delimited) file. Columns with commas in the text are enclosed in double quotes.
2. In Access, import the file as Text, with a comma delimiter and Text Qualifier = double quote.
3. After import, edit the table description to correct the field lengths.
Illustrates:
1. use of IIf to programmatically set value of a field.
2. creation of a new field (usng IIf)
3. name change of existing field (AS xxx)
The IIf code is an IF … THEN … ELSE … construct.
SELECT
[RCs with BF w/o NA].[RS CD],
[RCs with BF w/o NA].[BF CD],
[RCs with BF w/o NA].[CHAR TYPE CD],
[RCs with BF w/o NA].[CHAR SRC FLG],
IIf([CHAR TYPE CD]="AGENDUSE",[CHAR SRC FLG],"") AS AGENDUSE,
IIf([CHAR TYPE CD]="BILLER",[CHAR SRC FLG],"") AS BILLER,
IIf([CHAR TYPE CD]="CARE",[CHAR SRC FLG],"") AS CARE,
IIf([CHAR TYPE CD]="CUSTCRG",[CHAR SRC FLG],"") AS CUSTCRG,
IIf([CHAR TYPE CD]="DACREDIT",[CHAR SRC FLG],"") AS DACREDIT,
IIf([CHAR TYPE CD]="DCL",[CHAR SRC FLG],"") AS DCL,
IIf([CHAR TYPE CD]="ESP-CHRG",[CHAR SRC FLG],"") AS [ESP-CHRG],
IIf([CHAR TYPE CD]="ESP-DISC",[CHAR SRC FLG],"") AS [ESP-DISC],
IIf([CHAR TYPE CD]="ESP-KWH",[CHAR SRC FLG],"") AS [ESP-KWH],
IIf([CHAR TYPE CD]="MDMACRED",[CHAR SRC FLG],"") AS MDMACRED,
IIf([CHAR TYPE CD]="MTRCHRGE",[CHAR SRC FLG],"") AS MTRCHRGE,
IIf([CHAR TYPE CD]="SENIOR",[CHAR SRC FLG],"") AS SENIOR,
IIf([CHAR TYPE CD]="SERVPHAS",[CHAR SRC FLG],"") AS SERVPHAS,
IIf([CHAR TYPE CD]="TOT-CODE",[CHAR SRC FLG],"") AS [TOT-CODE], I
If([CHAR TYPE CD]="VOLTLVL",[CHAR SRC FLG],"") AS VOLTLVL,
IIf([APPL IN CONT SW]="N"," ",[APPL IN CONT SW]) AS [CONT RIDER],
IIf([VAL IN CONT SW]="N"," ",[VAL IN CONT SW]) AS [CONT VALUE],
IIf([EXEMPT IN CONT SW]="N"," ",[EXEMPT IN CONT SW]) AS [TAX EXEMPT]
FROM [RCs with BF w/o NA]
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 116 of 119
Microsoft Access Techniques
WHERE ((([RCs with BF w/o NA].[RS CD])="A10P" Or ([RCs with BF w/o NA].[RS
CD])="E1" Or ([RCs with BF w/o NA].[RS CD])="E19S" Or ([RCs with BF w/o NA].[RS
CD])="G1" Or ([RCs with BF w/o NA].[RS CD])="GNR1 "));
Character Replacement in SELECT
Can be done by a single query. Use a WHERE phrase to limit the character replacement to the records in error. If there is more than one character to replace, use a UNION.
SELECT ID, Filename, REPLACE(Filename, “%”, “ “) AS NewFilename, “%” As Error
FROM Test
WHERE InStr(Filename, “%”) > -0
UNION
SELECT ID, Filename, REPLACE(Filename, “#”, “ “) AS NewFilename, “#” As Error
FROM Test
WHERE InStr(Filename, “#”) > -0
UNION
SELECT ID, Filename, REPLACE(Filename, “~”, “ “) AS NewFilename, “~” As Error
FROM Test
WHERE InStr(Filename, “~”) > -0
UNION
SELECT ID, Filename, REPLACE(Filename, “&”, ““) AS NewFilename, “&” As Error
FROM Test
WHERE InStr(Filename, “&”) > -0
UNION
SELECT ID, Filename, REPLACE(Filename, “*”, “ “) AS NewFilename, “*” As Error
FROM Test
WHERE InStr(Filename, “*”) > -0
UNION
SELECT ID, Filename, REPLACE(Filename, “[“, “ “) AS NewFilename, “[“ As Error
FROM Test
WHERE InStr(Filename, “[“) > -0
UNION
SELECT ID, Filename, REPLACE(Filename, “]”, “ “) AS NewFilename, “]” As Error
FROM Test
WHERE InStr(Filename, “]”) > -0
UNION
SELECT ID, Filename, REPLACE(Filename, “:”, “ “) AS NewFilename, “:” As Error
FROM Test
WHERE InStr(Filename, “:”) > -0
UNION
SELECT ID, Filename, REPLACE(Filename, “<“, “ “) AS NewFilename, “<“ As Error
FROM Test
WHERE InStr(Filename, “<“) > -0
UNION
SELECT ID, Filename, REPLACE(Filename, “>“, “ “) AS NewFilename, “>“ As Error
FROM Test
WHERE InStr(Filename, “>“) > -0
UNION
SELECT ID, Filename, REPLACE(Filename, “?”, “ “) AS NewFilename, “?” As Error
FROM Test
WHERE InStr(Filename, “?”) > -0
UNION
SELECT ID, Filename, REPLACE(Filename, “+”, “ “) AS NewFilename, “+” As Error
FROM Test
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 117 of 119
Microsoft Access Techniques
WHERE InStr(Filename, “+”) > -0;
Creating a Table
You can create a table by importing an XLS file: with DoCmd.TransferSpreadsheet.
The text field sizes are 255 and there is no Unicode compression (see DDL below).
You can create a table from the results of a SELECT query:
SELECT * INTO MigrateWorksheet FROM FilesToMigrate where FilesToMigrate is a SELECT . . . FROM CandidateFiles query.
The field types, sizes, and Unicode compression are copied intact from the source table, except for type Hyperlink (called Anchor on the Documenter report) which reverts to text. There is no index.
[put INSERT statements here]
You can use a data definition query to change the field types and sizes. But it cannot set type =
Hyperlink. And it cannot set compression on after the table has been created.
You can use a data definition query to set an index.
Data Definition Language (DDL)
You can create a table with SQL:
CREATE [TEMPORARY] TABLE table (field1 type [(size)] [NOT NULL] [WITH
COMPRESSION | WITH COMP] [index1] [, field2 type [(size)] [NOT NULL] [index2]
[, ...]] [, CONSTRAINT multifieldindex [, ...]])
About compression: Microsoft Access 2000 and later uses the Unicode character‐encoding scheme to represent the data in a Text, Memo, or Hyperlink field. Unicode represents each character as two bytes, so the data in a Text, Memo, or Hyperlink field requires more storage space than it did in Access 97 or earlier, where each character is represented as one byte.
To offset this effect of Unicode character representation and to ensure optimal performance, the default value of the Unicode Compression property for a Text, Memo, or Hyperlink field is Yes.
When a fieldʹs Unicode Compression property is set to Yes, any character whose first byte is 0 is compressed when it is stored and uncompressed when it is retrieved. Because the first byte of a
Latin character—a character of a Western European language such as English, Spanish, or
German—is 0, Unicode character representation does not affect how much storage space is required for compressed data that consists entirely of Latin characters.
How you create a table governs the value of compression:
When you create a table with the Access GUI, the Text, Memo, and Hyperlink fields have by default compression = yes.
When you copy a table, or create a table with a SELECT INTO query, the new table has the compression settings of the source table.
When you create a table with DoCmd.TransferSpreadsheet, these fields have compression = no. If the amount of data is large, it can be better to create the table with the GUI or DDL
SQL before running the TransferSpreadsheet; this will conserve file space.
Note: A DDL query cannot change the compression on an existing table.
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 118 of 119
Microsoft Access Techniques
You can change an existing table with SQL:
ALTER TABLE table {ADD {COLUMN field type[(size)] [NOT NULL] [CONSTRAINT index]
|
ALTER COLUMN field type[(size)] |
CONSTRAINT multifieldindex} |
DROP {COLUMN field I CONSTRAINT indexname} }
You can add an index to an existing table with SQL:
CREATE [ UNIQUE ] INDEX index
ON table (field [ASC|DESC][, field [ASC|DESC], ...])
[WITH { PRIMARY | DISALLOW NULL | IGNORE NULL }]
Data Types
Hyperlink: A data type for an Access database field that stores hyperlink addresses. An address can have up to four parts and is written using the following format: displaytext#address#subaddress#. This data type cannot be set in DDL SQL.
Text: In a Microsoft Access database, this is a field data type. Text fields can contain up to 255 characters or the number of characters specified by the FieldSize property, whichever is less.
Memo: In a Microsoft Access database, this is a field data type. Memo fields can contain up to
65,535 characters.
Datetime: Stores date and time between years 100 and 9999.
Integer: Stores an long integer with a value between ‐2,147,483,648 and 2,147,483,647 in 8 bytes.
Decimal: Stores a decimal number in 17 bytes.
Money: Stores a number in 8 bytes.
Bit: Stores a binary (yes/no) value in 1 byte.
The following create table statement creates a test table with all of the DDL available to Microsoft
Access data types:
CREATE TABLE TestAllTypes
(
MyText TEXT(50),
MyMemo MEMO,
MyByte BYTE,
MyInteger INTEGER,
MyLong LONG,
MyAutoNumber COUNTER,
MySingle SINGLE,
MyDouble DOUBLE,
MyCurrency CURRENCY,
MyReplicaID GUID,
MyDateTime DATETIME,
MyYesNo YESNO,
MyOleObject LONGBINARY,
MyBinary BINARY(50)
)
Note: You cannot create “AutoNumber Replication,” “HyperLink,” or “Lookup” type fields using a Microsoft Access DDL SQL statement. These field types are not native Jet field types and can be created and used only by the Microsoft Access user interface. The MyBinary field above is a special fixed‐length binary field, which cannot be created via the Microsoft Access user interface but can be created using a SQL DDL statement.
Revision: 9/2/2012
Copyright 2001–2012 by Susan J. Dorey
Page 119 of 119
Download
Advertisement
Key features
Data management techniques
Form and report design
Application security
VBA coding practices
Object referencing
Frequently asked questions
You can create a table by using the "Create Table" feature in Access or by using the Data Definition Language (DDL).
Access supports various form types, including simple data entry forms, forms for viewing data, and forms that provide a user interface for specific tasks.
Lookup tables are used to enforce data integrity and provide users with a list of valid values. They can be used for fields like State or Department.
Macros automate tasks in Access. They can be used to open a form, run a query, or perform other actions.
You can debug VBA code in Access using the Visual Basic Editor. Utilize breakpoints and the "Step Into" feature to analyze code execution.