Introduction to SQL (Structured Query Language)

Level:
Level3

Written By TheVBProgramer.

This tutorial is not directly related to Visual Basic 6. But you will use this information heavily when writing any VB6 program that accesses a database. This teaches you all the basics and then some of the SQL language - it does so using Access databases. The SQL tutorial is pretty lengthy, but if you press through it you will really understand how database programming works.

Prerequisites

This tutorial presumes that the reader has a working knowledge of basic database table design principles, including basic normalization and relationships (one-to-many, one-to-one, many-to-many). Once a database has been designed and its tables have been populated with data, SQL can be used to manipulate the data in those tables.

 

Tutorials on database normalization and relationships can be found on various Internet sites. Even without this background, you may be able to glean some of this knowledge by going through the exercises in this tutorial.

 

You will need to have MS-Access 2000 (or higher) installed on your system to perform the examples presented in this tutorial. For one of the examples, you will also need MS-Excel.

 

About this Tutorial

 

The sample database used for this tutorial is a modified version of the sample "Northwind Traders" database, provided by Microsoft in Visual Studio and MS-Office.

 

The original database provided by Microsoft ("NWIND.MDB") contains many features that would detract from the purpose of this tutorial (in that the purpose of this tutorial is teach you how to write SQL to interact with database tables). The original database "shows off" many features of an MS-Access database: it contains many forms and reports; it also manipulates how some of the data appears when you open a table to view its contents (for example, a column may actually contain a numeric code, but the table datasheet view is set up to show the description corresponding to that code; also, in many cases a "display name" was set up for the column – for example, a column might actually be called "CustName" but it would appear as "Customer Name" when you opened the table).

 

The modified version of the database (called "NWINDVBP.MDB") has stripped out all of the "extras" so that it contains only the tables, and when you open a given table, you will see the true contents of the columns in that table.

 

Download the "NWINDVBP.MDB" database here.

 

A Note on Terminology

 

In this tutorial, the term record will be used interchangeably with the term row; and the term field will be used interchangeably with the term column.

 

 

Introduction to SQL

 

SQL (Structured Query Language) is a language designed to work with relational databases. Most people pronounce it "sequel", although others insist it must be pronounced "ess cue ell". I believe either pronunciation is fine.

 

In the mid 1970s, SQL was developed under the name SEQUEL (for Structured English Query Language?) at the IBM San Jose research facilities to be the data manipulation language for IBM's prototype relational model DBMS called "System R". In 1980, the language was renamed SQL to avoid confusion with an unrelated hardware product called SEQUEL.

 

SQL is currently used (and has been for quite some time) as the data manipulation language for most relational database management products on the market today. This includes IBM's DB2, Oracle, XBase (dBase, FoxPro, etc.), MS SQL Server, and Access. Although there are various SQL "standards" (SQL-89, SQL-92, etc.), there are variations in the "dialects" of SQL "spoken" by the different vendors. For example, there are some things you can do in Oracle SQL that you can't do with Access, and vice-versa.

 

On its own, SQL is a "non-procedural" language, meaning a program is not typically written in "straight SQL". When used on its own, a SQL command is given at a command-line interface provided by the DBMS software. You can then view the results of the single SQL command. Some DBMS's support SQL scripts (also called "stored procedures"), which is a file containing multiple SQL statements that are executed one after the other. SQL statements can also be embedded in a "host" language (like VB, C, COBOL, etc.), where a SQL statement can be executed and have its results processed by the host language.

 

SQL accomplishes many powerful tasks with a mere seven statements: SELECT, UPDATE, INSERT, DELETE, CREATE, ALTER, and DROP. Each of these seven statements fall into one of two categories: DML (Data Manipulation Language) statements or DDL (Data Definition Language) statements. These statements are summarized as follows:

 

DML Statements

 

SELECT Enables you to select one or more columns from one or more tables in the database. The results can be simply viewed, or can be used as the basis for a form or report, or, in the case of embedded SQL, can be processed as a temporary table (called a "recordset" in Access, called a "cursor" in other DBMSs).

 

UPDATE Enables you to update the data in one or more columns of one or more rows in a table.

 

INSERT Enables you to append rows to an existing table.

 

DELETE Enables you to delete one or more rows from an existing table.

 

 

DDL Statements

 

CREATE Enables you to create a new table, or to create a new index on an existing table.

 

ALTER Enables you to modify the structure of an existing table (by adding or deleting columns).

 

DROP Enables you to delete a table

 

 

The Northwind Traders Database

 

This tutorial uses the database for Northwind Traders, a fictional company that is a distributor of specialty food items. The link to download the database file, NWINDVBP.MDB, is provided above.

 

The Northwind Traders database consists of eight tables, as shown below (to view this in Access, go to Tools à Relationships):

 

 

 

 

How to do Command-line SQL in Access

 

·         Open the database that you want to work with (in this case, NWINDVBP.MDB).

 

·         Select Queries from the Objects sidebar, then click New:

 

 

·         The New Query dialog box appears (with "Design View" pre-selected as the default). Click OK:

 

 

·         The Show Table dialog box appears (note: your list of table names will not initially contain all of the table names shown here). Click Close:

 


·         The leftmost button on the Access toolbar should say "SQL". Click that button:

 

 

 

·         A text-entry box will appear (with the word "SELECT" pre-entered and highlighted). This is where you type your SQL query:

 

 

·         Try one now. Type the following in the text-entry box:

 

SELECT CustomerID, CompanyName, ContactName

FROM Customers

 

 

Note: SQL is NOT case-sensitive. You can enter keywords, table names, and field names in either upper- or lower-case letters (or a combination of the two). The only time case-sensitivity is an issue is when you are dealing with quoted strings.

 

·         To run the query, click the Run button on the toolbar (it's the "exclamation point" icon):

 

 

·         Access then displays the results of the query in a datasheet view:

 

 

 

·         To return to SQL view, select that option from the drop-down list of the leftmost toolbar icon:

 

 

 

Once you have returned to SQL view, you can overwrite the SQL command that you entered with the next SQL query you wish to enter. Before you overwrite the existing query, you can save it, as explained below.


 

·         FYI: To see the graphical representation of the SQL query that you entered, select the "Design View" option :

 

 

 

Whenever you write a query in SQL, Access builds the graphical representation of that query (if possible) behind the scenes (certain types of SQL queries cannot be represented graphically). Conversely, whenever you build a query graphically, Access generates the equivalent SQL statement behind the scenes.

 

Saving Queries

 

To save a query in the Access database, click the Save button (the diskette icon) on the Access toolbar. This will enable you to recall the query from the Queries tab in Access.

 

If you wish to only save the SQL statement (but not save the query in Access), you can select the text you entered in SQL view, copy it, then paste it into another application (such as Notepad, Word, or the VB code editor). Conversely, you can type up a SQL query in Notepad or Word, copy it, then paste it into the SQL View text-entry screen.

 

When you are at the point where you are writing a VB application that requires embedded SQL statements, you can use the graphical query capabilities of Access to "cheat". For example, if you can't recall exactly how to phrase a particular SQL statement, you can build a test query in Access with the graphical designer and run it. If it produces the desired results, you can switch over to SQL View and "steal" the code (i.e., copy it from Access and paste into VB). However – there is no substitute for simply "knowing" how to get the job done – and you may need to work with a DBMS that does not have a graphical designer for queries.

 

For each example in the following tutorial, please key in and run the SQL commands as shown. The SQL commands to key in will be shown in bold Courier, like the following:

 

SELECT CustomerID, CompanyName, ContactName

FROM Customers

 

The expected results of each query will also be shown, so that you can compare them to your results.

 

 

Part I: Single-Table Queries

 

The Basic SELECT Query

 

The SELECT query retrieves one or more columns (fields) from a table. The basic syntax is:

 

SELECT field1 [, field2, ... fieldn] FROM tablename

 

Notes: If more than one field is specified, each field must be separated with a comma. If you want to select ALL fields from a table, you can use an asterisk (*) instead of a list of all the fields.

 

Example 1:

Retrieve all columns and all rows from the Employees table.

 

SELECT * FROM EMPLOPYEES

 

 

Example 2:

Retrieve the Product ID, product name, and unit price from all rows of the Products table:

 

SELECT ProductID, ProductName, UnitPrice

FROM Products

 

 

Note: SQL statements can be entered on multiple lines, as in the query above. A recommended practice is to start each clause of the SQL statement on a separate line. This is a style consideration only; it has no effect on the interpretation of the statement.

 

Adding a WHERE Clause

 

By adding an appropriate WHERE clause to a SELECT statement, you can limit the number of rows (records) returned by the query. The WHERE clause specifies a condition that must be met in order for that row be returned.

 

Note: In the WHERE clause, numeric literals have no delimiters, string literals are delimited by single quotes (') (although Access will also accept double quotes(")), and date delimiters are delimited by the number sign (#). Delimiting dates with the number sign is specific to Access; most other DBMS' use the single quote as the date delimiter.

Example 3:

What is the name for product ID 19?

 

SELECT ProductName

FROM Products

WHERE ProductID = 19

 

 

Example 4:

Which customers are from Mexico? (Show Customer ID, company name, contact name, and contact title in the results.)

 

SELECT CustomerID, CompanyName, ContactName, ContactTitle

FROM Customers

WHERE Country = 'Mexico'

 

 

Example 5:

Which employees were hired on October 17, 1993? (Show employee first and last name, and title in the results.)

 

SELECT FirstName, LastName, Title

FROM Employees

WHERE HireDate = #10/17/1993#

 

 

Compound Conditions (Using AND and OR)

 

Example 6:

Which meat/poultry products (CategoryID = 6) have less than 10 units in stock? (Show product ID, product name, category ID, and units in stock in the results.)

 

SELECT ProductID, ProductName, CategoryID, UnitsInStock

FROM Products

WHERE CategoryID = 6 AND UnitsInStock < 10

 

 

Example 7:

Which items in the Product table are classified as meat/poultry or have less than 10 units in stock? (Show product ID, product name, category ID, and units in stock in the results.)

 

SELECT ProductID, ProductName, CategoryID, UnitsInStock

FROM Products

WHERE CategoryID = 6 OR UnitsInStock < 10

 

 

You can join multiple conditions using AND and OR. When both AND and OR are used in the WHERE clause, "AND" takes precedence. This precedence can be overridden by using parentheses. Examples 8 and 9 illustrate this:

 

Example 8:

Show the product name, units in stock, category ID, and unit price for seafood products (category ID = 8) that have at least 100 units in stock, or for any item whose unit price is greater than $50.

 

SELECT ProductName, UnitsInStock, CategoryID, UnitPrice

FROM Products

WHERE UnitsInStock >= 100

AND CategoryID = 8

OR UnitPrice > 50

 

Example 9:

Show the part product name, units in stock, category ID, and unit price for products that have at least 100 units in stock, and that are either classified as seafood (category ID = 8) or have a unit price greater than $50.

 

SELECT ProductName, UnitsInStock, CategoryID, UnitPrice

FROM Products

WHERE UnitsInStock >= 100

AND (CategoryID = 8

OR UnitPrice > 50)

 

 

Using NOT

 

Example 10:

Show the company name, contact name, and country for all non-US suppliers.

 

SELECT CompanyName, ContactName, Country

FROM Suppliers

WHERE NOT (Country = 'USA')

 

 

Note: This query could also be coded as:

 

SELECT CompanyName, ContactName, Country

FROM Suppliers

WHERE Country <> 'USA'

 

Some DBMS' use "!=" for "not equal to" in addition to or instead of "<>".

 

Using BETWEEN / AND

 

Example 11:

Show the Product ID, product name, and unit price for all products that have a unit price between $10 and $15 (inclusive):

 

SELECT ProductID, ProductName, UnitPrice

FROM Products

WHERE UnitPrice BETWEEN 10 AND 15

 

Note: This query could also be coded as:

 

SELECT ProductID, ProductName, UnitPrice

FROM Products

WHERE UnitPrice >= 10 AND UnitPrice <= 15

 

Example 12:

Show the Order ID, Customer ID, and order date for orders that occurred between February 1 and February 7, 1995.

 

SELECT OrderID, CustomerID, OrderDate

FROM Orders

WHERE OrderDate BETWEEN #2/1/1995# AND #2/7/1995#


 

Reminder: In Access SQL, Date literals must be delimited by pound signs (#). In most other database systems, dates are delimited with single quotes (same as strings).

Also: Queries based on dates become slighltly more involved if the dates have a time component to them (the dates in this database do not have a time component, but they could, because Date/Time fields can store both date and time together). If the OrderDate field contained a time component, you would have to write the WHERE clause of the above query like this:

 

WHERE OrderDate BETWEEN #2/1/1995# AND #2/7/1995 11:59:59PM#

- or -

WHERE OrderDate >= #2/1/1995# AND OrderDate < #2/8/1995#

 

 

Using Computed Columns (Expressions)

 

In the list of fields to be selected, you can specify an expression (arithmetic or string) that consists of a combination of fields and/or literals. In Access SQL, an expression can also incorporate a VB function such as DateAdd, Format$, Left$, etc. (although such expressions would not be accepted in non-Access environments, such as Oracle or SQL Server – however, those other DBMS environments have their own vendor-specific functions that can be used in expressions).

 

Example 13:

Show the OrderID, ProductID, UnitPrice, Quantity, Discount, and line item total for order line items that total at least $300.

 

SELECT OrderID, ProductID, UnitPrice, Quantity, Discount, Format$(UnitPrice * Quantity * (1 + Discount), "Fixed")

FROM [Order Details]

WHERE (UnitPrice * Quantity * (1 + Discount)) >= 300

 

 

Note that Access generates a default name for computed columns in the form Expr####. You can override this default name by using an alias for the column name via the AS clause (see the next example).

 

Note also that the table "Order Details" has an embedded space in its name. Although this is not good practice, Access will allow it for all of its objects (tables, columns, queries, etc.). When an object name contains embedded spaces (and other odd characters), you must enclose it square brackets as was done in the example above.

 

Example 14:

Repeat Example 13, except call the computed column "LineItemTot".

 

SELECT OrderID, ProductID, UnitPrice, Quantity, Discount,

Format$(UnitPrice * Quantity * (1 + Discount), "Fixed") AS LineItemTot

FROM [Order Details]

WHERE (UnitPrice * Quantity * (1 + Discount)) >= 300

 

 

Note: Some database systems do not require the word AS to specify an alias (in those systems, the expression is separated from the alias name with just a blank space).

 

Using LIKE

 

A WHERE clause condition can use the pattern-matching capabilities of the LIKE operator. In Access SQL, the syntax for LIKE is identical the VB syntax. In other database systems, the syntax for LIKE may vary (for example, Oracle uses a percent sign (%) instead of an asterisk (*) for a wildcard character).

 

Example 15:

Show company name, contact name, and title for customers whose contact person is considered a "manager".

 

SELECT CompanyName, ContactName, ContactTitle

FROM Customers

WHERE ContactTitle LIKE '*Manager*'

 

 

Using IN

 

The IN operator can be used in a WHERE clause condition to specify that a field must be equal to any of several values.

 

Example 16:

Show company name and address information for all suppliers located in France, Germany, and Italy.

 

SELECT CompanyName, Address, City, Country, PostalCode

FROM Suppliers

WHERE Country IN ('France', 'Germany', 'Italy')

 

Note: This query could also be coded as:

 

SELECT CompanyName, Address, City, Country, PostalCode

FROM Suppliers

WHERE Country = 'France'

OR Country = 'Germany'

OR Country = 'Italy'

 

(As you can see, using IN in this case is much more concise.)

 

Sorting with the ORDER BY clause

 

You can sort the results of your query on any field or fields by using an ORDER BY clause.

 

Example 17-a:

Show the category ID, unit price, and product name for all products, sorted by unit price (low to high).

 

SELECT CategoryID, UnitPrice, ProductName

FROM Products

ORDER BY UnitPrice

 

Note: By default, ORDER BY sorts the data in ascending (low to high) sequence. You can specify an ascending or descending sort by using the keywords ASC or DESC, respectively. The last line of the above query could have been written:

 

ORDER BY UnitPrice ASC

 

Example 17-b:

Show the category ID, unit price, and product name for all products, sorted by unit price (high to low).

 

SELECT CategoryID, UnitPrice, ProductName

FROM Products

ORDER BY UnitPrice DESC

 

 

Example 18:

Show the category ID, unit price, and product name for all products, sorted by unit price (high to low) WITHIN category ID.

 

SELECT CategoryID, UnitPrice, ProductName

FROM Products

ORDER BY CategoryID, UnitPrice DESC

 

 

Using SQL Functions

 

The COUNT Function

 

The COUNT function in a SELECT statement returns a count of the number of records in a table (if the statement has a WHERE clause, it returns only the number of records that meet the specified condition).

 

The syntax for the COUNT function requires that the word COUNT be followed by a field name in parentheses; normally, you would place an asterisk between the parentheses to signify "any field": COUNT(*). The COUNT function counts records; it is not dependent on any particular field within a record.

 

Some database systems do not support the asterisk syntax on the COUNT function; on those systems the syntax COUNT(fieldname) must be used, and any field name would do.

 

Example 19:

How many products are classified as beverages (category ID 1)?

 

SELECT COUNT(*) AS BeverageCount

FROM Products

WHERE CategoryID = 1

 

The SUM Function

 

The SUM function in a SELECT statement returns the sum of a numeric field or expression for all of records in a table (if the statement has a WHERE clause, it sums that field only for the records that meet the specified condition).

 

Example 20:

How many order lines do we have, and what is their total value?

 

SELECT COUNT(*) AS OrderLineCount, SUM(UnitPrice * Quantity * (1 + Discount)) AS OrderLineTotal

FROM [Order Details]

 

 

Note: If you wanted to format the total, you could wrap the Format$ function around the SUM expression as follows:

 

SELECT COUNT(*) AS OrderLineCount,

Format$(SUM(UnitPrice * Quantity * (1 + Discount)), "Currency") AS OrderLineTotal

FROM [Order Details]

 

 

The AVG, MAX, and MIN Functions

 

An AVG, MAX, or MIN function in a SELECT statement returns the average value, maximum value, or minimum value, respectively, of a numeric field for all of records in a table (if the statement has a WHERE clause, the function is performed for that field only for the records that meet the specified condition).

 

Example 21:

Display the total order line value, average order line value, highest order line value, and lowest order line value.

 

SELECT Format$(SUM(UnitPrice * Quantity * (1 + Discount)), "Currency") AS OrderLineTotal,

Format$(AVG(UnitPrice * Quantity * (1 + Discount)), "Currency") AS AverageOrderLine,

Format$(MAX(UnitPrice * Quantity * (1 + Discount)), "Currency") AS HighestOrderLine,

Format$(MIN(UnitPrice * Quantity * (1 + Discount)), "Currency") AS LowestOrderLine

FROM [Order Details]

 

 

 

Using DISTINCT

 

Example 22-a:

As a verification, run the query below to see that any particular customer may have more than one order in the Orders table:

 

SELECT * FROM Orders ORDER BY CustomerID

 

 

Example 22-b:

Use the DISTINCT keyword to show each customer in the ORDERS table only once.

 

SELECT DISTINCT CustomerID FROM Orders

 

 

STOP. Do not get rid of the above query; we're going to save it shortly.

 

Now a problem is going to present itself. Suppose you are asked "how many customers have orders?" In Oracle and other DBMS' (but not Access), DISTINCT can be used as a function, which would enable you to satisfy this question using one query, like so:

 

SELECT COUNT(DISTINCT(CustomerID)) FROM Orders

 

Oracle would return the correct results, but attempting the above in Access would result in an error. What to do?

 

Sometimes it is necessary to run more than one query, back-to-back, to solve a particular problem (for example, the results of the first query would be used to "feed" the second query). This is exactly what we must do to answer the question "how many customers have orders?". Save the query you wrote in example 22-b as qryDistinctCust.

When you save a query, only the query definition is saved (when the query is run for the first time, it is compiled as well) – the output results of the query are not saved; they are recreated every time the query is run. FYI: In Access, saved queries are known as "QueryDefs" (at least, programmers call them that). In other database systems, saved queries may be called "views" or "stored procedures".

 

The "Make Table" (SELECT / INTO) Query

 

It is also possible to make a query that saves its results to a new table. Access calls this a "make table" query, and it is accomplished in SQL by using the INTO clause of the SELECT statement. (Note: Not all versions of SQL support SELECT / INTO).

 

Example 22-c:

The following query will save its results to a table named tblCustsWithOrders:

 

SELECT DISTINCT CustomerID AS CustNbr

INTO tblCustsWithOrders

FROM Orders

 

Access may warn you that this will create a permanent table and that you can't undo this action. If so, click OK and let Access do its thing. If you check the Tables tab in Access, you'll see that this table is now there.

 

 

You can check the results by either opening the table or by running the following query:

SELECT * FROM tblCustsWithOrders

 

 

To get a count of the number of unique customers in the ORDERS table, we can use the COUNT function on either the newly created query or on the newly created table.

 

Example 22-d:

Get a count of the number of unique customers in the ORDERS table by using the COUNT function on the saved qryDistinctCust query (note that Access allows you to use a saved query (QueryDef) in place of a table name in a SELECT query).

 

SELECT COUNT(*) AS CustCount FROM qryDistinctCust

 

 

Example 22-e:

Get a count of the number of unique customers in the ORDERS table by using the COUNT function on the new tblCustsWithOrders table.

 

SELECT COUNT(*) AS CustCount FROM tblCustsWithOrders

 

 

 

Subqueries

 

On the right-hand side of a conditional expression in a WHERE clause, you can use a subquery to return a comparison value. The subquery, which must return only one column, is executed first. The result of the subquery is then incorporated into the main query. If the subquery can only return a single value (one row, one column), then a relational operator (like = or >) can be used, as in the next two examples.

 

Example 23:

Show all fields of Order table for orders that were placed on the most recent order date.

 

SELECT *

FROM Orders

WHERE OrderDate = (SELECT MAX(OrderDate) FROM Orders)

 

 

The above query works as follows: the subquery

SELECT MAX(OrderDate) FROM Orders

will execute and return one value (the date 6/5/1996). You can verify that result by looking at the Order table – you'll see that the latest date for any order is 6/5/1996. That result (6/5/1996) is then used as the comparison value in the outer WHERE clause, effectively making it read:

WHERE OrderDate = #6/5/1996#"

 

Note: The dates in this table do not have a time component to them. If they did, the query would have to do a little more work to specify the desired date.

 

Example 24:

Show the OrderID, ProductID, UnitPrice, Quantity, Discount, and line item total for order lines that exceed the average order line total.

 

SELECT OrderID, ProductID, UnitPrice, Quantity, Discount,

Format$(UnitPrice * Quantity * (1 + Discount), "Fixed") AS OrderLineTotal

FROM [Order Details]

WHERE (UnitPrice * Quantity * (1 + Discount)) > (SELECT AVG(UnitPrice * Quantity * (1 + Discount))

FROM [Order Details])

 

 

The above query works as follows: the subquery

SELECT AVG(UnitPrice * Quantity * (1 + Discount)) FROM [Order Details]

will execute and return one value ($669.66). You can verify that by looking at the results of example 21. That result ($669.66) is then used as the comparison value in the outer WHERE clause, effectively making it read:

WHERE (UnitPrice * Quantity * (1 + Discount)) > 669.66

 

If the subquery can return multiple values (multiple rows, one column each), then the keyword IN must be used instead of a relational operator. This type of query is typically used in multi-table queries, which are presented in Part II of this document. The next example is a "sneak preview" of a multi-table query that uses a subquery that returns multiple values.

 

Example 25:

Show the orders will be shipped by either Speedy Express or Federal Shipping.

 

SELECT *

FROM Orders

WHERE ShipVia

IN (SELECT ShipperID FROM Shippers WHERE CompanyName IN ('Speedy Express', 'Federal Shipping'))

 

The above query works as follows: the subquery

SELECT ShipperID FROM Shippers WHERE CompanyName IN ('Speedy Express', 'Federal Shipping')

will execute and return a result set consisting of two rows (one row containing the ShipperID for Speedy Express, the other containing the ShipperID for Federal Shipping). This result set will then supply the values to the IN clause, as if the query was written as follows:

 

SELECT *

FROM Orders

WHERE ShipVia IN (1, 3)

 

Grouping Data with the GROUP BY Clause

 

When you group data, you create a query that produces one record for each unique value of a field (or combination of fields) in a table (limited by the WHERE clause, if there is one). Any of the SQL functions discussed earlier (COUNT, SUM, AVG, etc.) apply to the grouped record.

 

Example 26:

Show the order ID and order total for each order.

 

SELECT OrderID, SUM(UnitPrice * Quantity * (1 + Discount)) AS OrderTotal

FROM [Order Details]

GROUP BY OrderID

 

Using the HAVING clause

 

Just as the WHERE clause can be used to limit the rows that are included in the result of a SQL command, the HAVING clause can be used to limit the groups that are included.

 

Example 27:

Show the order number and order total for each order, but include only orders that have a total greater than $1000.

 

SELECT OrderID, SUM(UnitPrice * Quantity * (1 + Discount)) AS OrderTotal

FROM [Order Details]

GROUP BY OrderID

HAVING SUM(UnitPrice * Quantity * (1 + Discount)) > 1000

 

 

FYI: Even when you use an alias for a computed column, you must still use the expression, not the alias, in the HAVING clause (this also applies to the WHERE and ORDER BY clauses – if a computed column is used with either of these, it is the expression, not the alias, that must be specified.)


Example 28:

For each order, show the number of order lines that make up that order.

 

SELECT OrderID, Count(*) AS OrderLineCount

FROM [Order Details]

GROUP BY OrderID

 

 

 

Example 29:

For each order, show the number of order lines that make up that order; but only include orders containing three or more items.

 

SELECT OrderID, Count(*) AS OrderLineCount

FROM [Order Details]

GROUP BY OrderID

HAVING Count(*) >= 3

 

 

Example 30:

For each order, show the number of order lines that make up that order, but only for orders that include product IDs 4 or 5 (a "Chef Anton" product).

 

SELECT OrderID, Count(*) AS OrderLineCount

FROM [Order Details]

WHERE OrderID IN (SELECT OrderID FROM [Order Details] WHERE ProductID IN (4,5))

GROUP BY OrderID

 

 

In this example, the SQL interpreter must perform two "passes" behind the scenes. First it applies the WHERE clause to the table. From that resulting set of records, the grouping is performed.

 

Example 31:

For each order, show the number of order lines that make up that order, but only for orders that include product IDs 4 or 5 (a "Chef Anton" product) and that have at least three or more total items.

 

SELECT OrderID, Count(*) AS OrderLineCount

FROM [Order Details]

WHERE OrderID IN (SELECT OrderID FROM [Order Details] WHERE ProductID IN (4,5))

GROUP BY OrderID

HAVING Count(*) >= 3

 

 

As in the previous example, the SQL interpreter must perform a number of passes behind the scenes. First it applies the WHERE clause to the table. From that resulting set of records, the grouping is performed. From the grouped set of records, the HAVING clause is then applied.

 

Part II: Multiple-Table Queries (Joins)

 

One of the results of normalizing your tables is that most queries will draw on several tables in order to get the desired result. As a result, most of the queries you create will need to combine two or more tables. In Access SQL, tables are joined by specifying which fields of the tables you want to match on, either in a WHERE clause or in a JOIN clause.

 

Let's do an example first, then resume with a further explanation of how the join works.

 

Example 32-a:

List the order ID and product name for each order line on the Order Details table.

 

SELECT OrderID, ProductName

FROM [Order Details], Products

WHERE [Order Details].ProductID = Products.ProductID

ORDER BY OrderID

 

 

In the syntax for the above query, note the following:

 

·         Since we needed to draw from both the Order Details table and the Products table, both of those tables were specified in the FROM clause, separated by a comma.

 

·         When you join two or more tables and those tables share common field names, those field names must be qualified in the query – this is the case in the query above for the ProductID field (both the Order Details and Products tables have a field with that names). To qualify a field name, use the syntax tablename.fieldname.

 

·         To specify how the tables should be joined, a WHERE clause is used to specify a matching (equal) condition between the fields that link the two tables (usually, these are the fields that were involved in establishing a one-to-many relationship between the two tables).

 

To understand why the query works the way it does, let's explore a little relational database theory:

 

·         The relational model specifies that the first step in creating a join is to generate the Cartesian product of the two tables. The Cartesian product for two tables is another (virtual) table contains records made up of every possible combination of records from the two joined tables. In the case of the Order Details and Products tables, the Cartesian product would be a virtual table of 165935 records (2155 Order Details records X 77 Products records): i.e., the data for each and every Products row would be joined with each and every Order Details row.

 

·         From the Cartesian product, the records meeting the WHERE clause are extracted (thus, only records where the ProductID field matches are selected).

 

·         From the matched records, the desired columns (as specified in the SELECT clause) are extracted, resulting in the final result set.

 

To reduce the amount of typing required by qualifying the field names with the table names, you can use a short alias on the table names with the AS clause, as in the following example:

 

Example 32-b:

Modify the query in 32-a to use table name aliases:

 

SELECT OrderID, ProductName

FROM [Order Details] AS OD, Products AS P

WHERE OD.ProductID = P.ProductID

ORDER BY OrderID

 

The above will produce the same results as example 32-a.

 

Note: Some database systems do not require (and some will not allow) the word AS to specify an alias (in those systems, the table name is separated from the alias name with just a blank space).

 

Using INNER JOIN

 

As an alternative to specifying the join criteria in the WHERE clause, Access SQL allows you to specify the join criteria with the INNER JOIN clause, which is part of the FROM clause. The basic syntax is:

 

SELECT fields

FROM table1 INNER JOIN table2 ON table1.field = table2.field

 

The INNER JOIN syntax is not supported on all database systems, but it is on most (including SQL Server and more recent versions of Oracle).

 

Example 32-c:

List the order ID and product name for each order line on the Order Details table. Use the INNER JOIN clause to specify the join criteria.

 

SELECT OrderID, ProductName

FROM [Order Details] AS OD INNER JOIN Products AS P ON OD.ProductID = P.ProductID

ORDER BY OrderID

 

The above will produce the same results as examples 32-a and 32-b.

 

 

WHERE vs. INNER JOIN

 

On the one hand, specifying join criteria with the WHERE clause is universally acceptable on all database systems that use SQL. On the other hand, INNER JOIN is preferred in Access SQL, because this format makes the join criteria explicit, rather than inferring it from the WHERE clause – the WHERE clause is then reserved for selection criteria, rather than doing dual-duty as a join specifier.

 

Future examples in this tutorial will show joins using both formats.

 

Example 33:

List the order ID, customer ID, and order date together with the sales rep first name and last name for the sales rep who made the order for all orders made in the month of September, 1994.

 

SELECT OrderID, CustomerID, OrderDate, FirstName, LastName

FROM Orders AS O, Employees AS E

WHERE O.EmployeeID = E.EmployeeID

AND OrderDate BETWEEN #9/1/1994# AND #9/30/1994#

ORDER BY OrderID

 

-- or –-

 

SELECT OrderID, CustomerID, OrderDate, FirstName, LastName

FROM Orders AS O INNER JOIN Employees AS E ON O.EmployeeID = E.EmployeeID

WHERE OrderDate BETWEEN #9/1/1994# AND #9/30/1994#

ORDER BY OrderID

 

 

 

In addition to joining tables with the WHERE clause or INNER JOIN clause, you can also join tables by using IN with a subquery. The next example illustrates this.

 

Example 34:

Find the description for every product included in order number 10250.

 

SELECT ProductName

FROM [Order Details] AS OD, Products AS P

WHERE OD.ProductID = P.ProductID

AND OD.OrderID = 10250

 

-- or --

 

SELECT ProductName

FROM [Order Details] AS OD INNER JOIN Products AS P ON OD.ProductID = P.ProductID

WHERE OD.OrderID = 10250

 

-- or --

 

SELECT ProductName

FROM Products

WHERE ProductID IN (SELECT ProductID FROM [Order Details] WHERE OrderID = 10250)

 

 

The next example joins three tables together and shows three different ways to get the results (joining with WHERE, INNER JOIN, or nested subquery):

 

Example 35:

Find the order ID and order date for every order that includes a product with "Chef Anton" in the product name.

 

SELECT DISTINCT O.OrderID, OrderDate

FROM Orders AS O, [Order Details] AS OD, Products AS P

WHERE O.OrderID = OD.OrderID

AND OD.ProductID = P.ProductID

AND P.ProductName LIKE '*Chef Anton*'

 

-- or --

 

SELECT DISTINCT O.OrderID, OrderDate

FROM (Orders AS O INNER JOIN [Order Details] AS OD ON O.OrderID = OD.OrderID)

INNER JOIN Products AS P ON OD.ProductID = P.ProductID

WHERE P.ProductName LIKE '*Chef Anton*'

 

-- or --

 

SELECT DISTINCT O.OrderID, OrderDate

FROM Orders AS O

WHERE OrderID IN (SELECT OrderID

FROM [Order Details]

WHERE ProductID IN (SELECT ProductID

FROM Products

WHERE ProductName LIKE '*Chef Anton*'))

 

 

Note: The DISTINCT keyword was used because if a particular order contained more than one "Chef Anton" product, that OrderID would be duplicated in the resultset. We only want to see the unique OrderIDs (and their dates) for all orders that have one or more Chef Anton products.

 

Comprehensive Example

 

Example 36:

This query incorporates most of the major SQL clauses discussed so far. This query joins four tables together to show the Order ID, order date, customer (company name), employee name and order total for all orders made in the month of January 1995 that totalled $1500 or more.

 

SELECT O.OrderID, O.OrderDate, C.CompanyName, E.FirstName, E.LastName,

SUM(OD.UnitPrice * OD.Quantity * (1 + OD.Discount)) AS OrderTotal

FROM Orders AS O, [Order Details] AS OD, Customers AS C, Employees AS E

WHERE O.OrderID = OD.OrderID

AND O.CustomerID = C.CustomerID

AND O.EmployeeID = E.EmployeeID

AND O.OrderDate BETWEEN #1/1/1995# AND #1/31/1995#

GROUP BY O.OrderID, O.OrderDate, C.CompanyName, E.FirstName, E.LastName

HAVING SUM(OD.UnitPrice * OD.Quantity * (1 + OD.Discount)) >= 1500

 

-- or --

 

SELECT O.OrderID, O.OrderDate, C.CompanyName, E.FirstName, E.LastName,

SUM(OD.UnitPrice * OD.Quantity * (1 + OD.Discount)) AS OrderTotal

FROM ((Orders AS O INNER JOIN [Order Details] AS OD ON O.OrderID = OD.OrderID)

INNER JOIN Customers AS C ON O.CustomerID = C.CustomerID)

INNER JOIN Employees AS E ON O.EmployeeID = E.EmployeeID

WHERE O.OrderDate BETWEEN #1/1/1995# AND #1/31/1995#

GROUP BY O.OrderID, O.OrderDate, C.CompanyName, E.FirstName, E.LastName

HAVING SUM(OD.UnitPrice * OD.Quantity * (1 + OD.Discount)) >= 1500

 

 

Outer Joins

 

The INNER JOIN retrieves records only when there is a match in both tables. In some cases, you may want to retrieve the values from one table even when there are no matching values in the other joined table. For example, suppose you wanted a list of all employees showing the orders that they placed in a given week (if any). To accomplish this, you could perform an outer join between the Employees table and the Orders table.

 

Instead of using the keywords "INNER JOIN", you use "LEFT OUTER JOIN" or "RIGHT OUTER JOIN" (the keyword "OUTER" is optional; the keyword "LEFT" or "RIGHT" implies an outer join; in fact, in some DBMS', the keyword OUTER is not allowed).

 

Example 37:

List the employee first name and employee last name for all employees, together with the order IDs and order dates for orders made by that employee (if any) for the week of September 26 through September 30, 1994. (If an employee made more than one order during that time period, that employee will show up more than once.)

 

Note: In order for this query to produce the desired results, a table expression (sometimes called an in-line view or in-line table) is used as the second table being joined in the SQL statement. In many cases, most DBMS' will allow a table expression to be used where a table name is expected. The table expression SELECT * FROM Orders WHERE OrderDate BETWEEN #9/26/1994# AND #9/30/1994# specifies a subset of records from the Orders table for the desired date range.

SELECT E.FirstName, E.LastName, O.OrderID, O.OrderDate

FROM Employees AS E

LEFT JOIN (SELECT * FROM Orders WHERE OrderDate BETWEEN #9/26/1994# AND #9/30/1994#) AS O

ON E.EmployeeID = O.EmployeeID

 

 

 

In the results above, for employees that don't have orders, the OrderID and OrderDate columns will contain NULL. This fact can be used in the type of query that asks the question, "which employees do NOT have orders?":

 

Example 38:

List the employee first name and employee last name for all employees for that had no orders for the week of September 26 through September 30, 1994.

 

SELECT E.FirstName, E.LastName, O.OrderID, O.OrderDate

FROM Employees AS E

LEFT JOIN (SELECT * FROM Orders WHERE OrderDate BETWEEN #9/26/1994# AND #9/30/1994#) AS O

ON E.EmployeeID = O.EmployeeID

WHERE O.OrderID IS NULL

 

 
Self-Joins

 

It is possible to create a join between a table and a second instance of the same table. A common example is an Employees table in which the "ReportsTo" field (i.e., the employee's supervisor) contains EmployeeID values found in the Employees table itself.

 

The following example joins the Employees table to itself. The ReportsTo field in the first instance of the table is linked to the EmployeeID field in the second instance.

 

Example 39-a:

List the employee ID, last name, and first name for each employee, together with the last name and first name of that employee's supervisor.

 

SELECT E1.EmployeeID, E1.LastName, E1.FirstName,

E2.LastName, E2.FirstName

FROM Employees AS E1 INNER JOIN Employees AS E2

ON E1.ReportsTo = E2.EmployeeID

 

 

Because an inner join was specified, if the value in the ReportsTo field of any given record isn't also found in the EmployeeID field, the record isn't selected. This would leave out records where the ReportsTo field is NULL, perhaps indicating that the employee is a supervisor and doesn't report to another employee in the Employees table (as is the case for Andrew Fuller).

 

Example 39-b:

Revise the query written in exercise 41-a to use a LEFT JOIN, so that all employee records will be selected, whether or not they have a supervisor:

 

SELECT E1.EmployeeID, E1.LastName, E1.FirstName,

E2.LastName, E2.FirstName

FROM Employees AS E1 LEFT JOIN Employees AS E2

ON E1.ReportsTo = E2.EmployeeID

 

 

 
UNION Queries

 

A union query is one which creates a result set consisting of the results of two or more queries appended to one another with any duplicates removed.

 

Example 40:

List the employee first name and employee last name for employees that either placed orders on the week of September 26 through September 30, 1994, or employees that ever had an order containing a Chef Anton product (product IDs 4 or 5), or both. Include in the listing a column indicating which of these conditions was met.

 

SELECT FirstName, LastName, 'Had orders week of 9/26' AS ConditionMet

FROM Employees AS E INNER JOIN Orders AS O ON E.EmployeeID = O.EmployeeID

WHERE OrderDate BETWEEN #9/26/1994# AND #9/30/1994#

UNION

SELECT FirstName, LastName, 'Sold Chef Anton'

FROM (Employees AS E INNER JOIN Orders AS O ON E.EmployeeID = O.EmployeeID)

INNER JOIN [Order Details] AS OD ON O.OrderID = OD.OrderID

WHERE OD.ProductID IN (4, 5)

 

 

The rules for union queries in Access SQL are as follows:

 

·         All queries in a UNION must request the same number of fields, but they don't have to be the same size or data type (this restriction does exist in other database systems).

 

·         Use aliases only in the first SELECT statement, because they are ignored in all others

 

·         You can use a GROUP BY or HAVING clause in each query argument to group the returned data

 

·         You can use an ORDER BY clause at the end of the last query argument to display the returned data in a specified order. In the ORDER BY clause, refer to fields by what they are called in the first SELECT statement.

Part III: Updating Data and DDL Queries

 

It goes without saying that caution should be exercised whenever you run a query that can change or delete data in a table. It is a good idea to backup your database or to work with test tables when you are in a testing mode.

 

The UPDATE Query

 

Example 41:

Change the contact name for Customer ID "AROUT" to "John Smith"

 

·         First, run this SELECT query to look at the existing data:

 

SELECT CustomerID, ContactName

FROM Customers

 

(Note that the contact name for Customer ID "AROUT" is '"Thomas Hardy".)

 

·         Next, run the UPDATE query:

 

UPDATE Customers

SET ContactName = 'John Smith'

WHERE CustomerID = 'AROUT'

 

·         Finally, run another SELECT query to verify the change that you made:

 

SELECT CustomerID, ContactName

FROM Customers

 

(Note the change)

 

Note: Without the WHERE clause in the UPDATE, ALL records would have the ContactName field updated to 'John Smith' (and that wouldn't be good).

 

Example 42:

Due to an increase in the price of sugar, you must increase the unit price of all products in the "Confections" category (Category ID 3) by 3%.

 

·         First, run a SELECT query to look at the existing data:

 

SELECT * FROM Products ORDER BY CategoryID

 

 

·         Next, run the UPDATE query:

 

UPDATE Products

SET UnitPrice = UnitPrice * 1.03

WHERE CategoryID = 3

 

·         Finally, run another SELECT query to verify the changes that you made:

 

SELECT * FROM Products ORDER BY CategoryID

 

 

 

Although not shown in the examples, you can change multiple fields with the SET clause by separating each "column = value" item with a comma:

 

UPDATE Customers SET ContactName = 'John Smith', ContactTitle = 'Sales Manager', FAX = '123-456-7890' WHERE ...

 

 

 

Combining UPDATE with INNER JOIN

 

A very useful feature of the UPDATE statement is its ability to join tables so that you can update data in one table based on data in another table. Such an update is sometimes called a "batch update" or "mass update". (Not all database systems allow this form of the UPDATE statement.)

 

For example, suppose price updates for certain products were entered into an Excel spreadsheet and you needed to update the UnitPrice field of the Products table with those new prices. You could link to the Excel spreadsheet (which would cause Access to look at the spreadsheet as if it were a table), then run the UPDATE query using the Products table and the linked table. The example below shows you how to do all that:

 

·         Open Excel, and create the simple spreadsheet shown below. Save the spreadsheet as PriceUpdate.xls (it does not matter what folder you save it to, but you will need to remember the location for the steps that follow), then exit Excel.

 

 

·         Back in Access (in our NWINDVBP database), go to the File menu and select Get External Data -> Link Tables, as shown below:

 

 

 

·         In the Link dialog box that comes up, select "Microsoft Excel(*.xls)" from the "Files of type" drop-down list, navigate to the folder where you saved the spreadsheet, select the PriceUpdate.xls file and click the Link button:

 

 

·         The Link Spreadsheet Wizard appears. The initial pre-selections should be correct, so click Next.

 

 

·         On the next page of the wizard, ensure that the "First row contains column headings" box is checked (see below). After checking the box (or verifying that it is checked), click Next.

 

 

·         On the last page of the wizard, type PriceUpdate for the linked table name. When you are done, click Finish.

 

 

·         You should get a message that the wizard completed successfully. You should then see an entry for the linked table in the Tables tab of the Access database (it will appear in the list of tables with a special icon):

 

 

At this point, PriceUpdate can be used just like any other table in the database.

 

Example 43:

Update the unit price data in the Products table with data for the corresponding products in the PriceUpdate spreadsheet.

 

·         First, run a SELECT query to look at the existing data (for the sake of the example, we know that we are going to update four particular products):

 

SELECT ProductID, ProductName, UnitPrice

FROM Products

WHERE ProductID IN (4, 5, 14, 17)

 

 

·         Next, run the UPDATE query:

 

UPDATE Products INNER JOIN PriceUpdate

ON Products.ProductID = VAL(PriceUpdate.ProductID)

SET Products.UnitPrice = PriceUpdate.UnitPrice

 

Note: The VAL function was used on the PriceUpdate.ProductID field because when the PriceUpdate spreadsheet was linked, Access treated that field as text rather than numeric (and the Link Wizard does not provide a way to specify the data type of the linked fields). The ProductID from the spreadsheet must be treated as a number in order to join with the ProductID from the Products table. Access did not have a problem maintaining the numeric data type of the unit price, which contains a decimal point.

 

When you run the above UPDATE query, you may get a prompt similar to the following. For our example, you should respond Yes.

 

 

·         Finally, re-run your SELECT query from above to see the results of your changes:

 

SELECT ProductID, ProductName, UnitPrice

FROM Products

WHERE ProductID IN (4, 5, 14, 17)

 

 

The DELETE Query

 

Example 44:

Mario Pontes from the Hanari Carnes company calls to tell you to remove the Manjimup Dried Apples from the order that was placed on August 8, 1994. You determine that this is order ID 10250 and that the product in question is Product ID 51.

 

·         First, run this SELECT query to look at the existing data:

 

SELECT * FROM [Order Details]

WHERE OrderID = 10250

 

 

·         Next, run the DELETE query:

 

DELETE FROM [Order Details]

WHERE OrderID = 10250

AND ProductID = 51

 

Note that you must specify BOTH OrderID AND the ProductID so that you delete the one exact row form the table. Otherwise, you will delete too much data (and your other customers will not be happy!)

 

When you run the above DELETE query, you may get a prompt from Access telling you that 1 row will be deleted and that the action cannot be undone. For our example, you should respond Yes.

 

·         Finally, re-run the SELECT query from above to verify the results:

 

SELECT * FROM [Order Details]

WHERE OrderID = 10250

 

 

Warning: If you issue a DELETE statement without a WHERE clause, you will delete ALL records in that table (the table itself and its structure will remain intact). To completely remove a table, use the DROP TABLE statement.

 

Although a hands-on example will not be given here, just as an UPDATE query can update records in one table based on matching data in another table, a DELETE query can also be based on a multiple-table join (records in one table can be deleted based on matching values in another table).

 

This (non-hands-on) example query joins the Categories table to the Products table, and deletes records in the Products table that match the selection criterion specified for the Categories table:

 

DELETE Products.*

FROM Categories INNER JOIN Products

ON Categories.CategoryID = Products.CategoryID

WHERE Categories.CategoryName = 'Beverages'

 

 

The Append Query (INSERT INTO)

 

The INSERT INTO statement has two basic formats. To insert one row into a table, you can use the INSERT INTO ... VALUES format; to insert multiple rows into a table from another table, you can use the INSERT INTO ... SELECT format. The INSERT INTO ... VALUES format will be shown first.

 

Example 45:

Insert a record for our new shipper, International Parcel Service. Their phone number is (800) 888-9999.

 

INSERT INTO Shippers (CompanyName, Phone)

VALUES ('International Parcel Service', '(800) 888-9999')

 

To check out the results, do a SELECT query:

 

SELECT * FROM Shippers

 

 

Note that in the INSERT statement above, the ShipperID was NOT specified. This is because the ShipperID field is defined as an Autonumber field, thus, whenever a new record is added to the Shippers table, the ShipperID field will automatically populate with the next available number.

 

In the next example, we will use the SQL DDL statement CREATE TABLE to create a new table. Then we will use INSERT INTO with the SELECT option to populate this new table with some data from the Customers table.

 

Creating a New Table

 

The Access SQL CREATE TABLE command has this basic syntax:

 

CREATE TABLE tablename (

field1 type [(size)] [NOT NULL] [single-field CONSTRAINT clause]

[, field2 type [(size)] [NOT NULL] [single-field CONSTRAINT clause]

[, ...]]

[, mutliple-field CONSTRAINT clause [, ...]])

 

The CREATE TABLE statement has these parts:

 

tablename

The name of the table to be created.

field1, field2

The name of field or fields to be created in the new table. You must create at least one field.

type

The data type of field in the new table. The keywords that can be used are shown below:

 

Table field data type in Access UI

CREATE TABLE keyword(s)

Yes/No

BOOLEAN, BIT, LOGICAL, LOGICAL1, YESNO

Number (Byte)

BYTE, INTEGER1

AutoNumber (Long Integer)

COUNTER, AUTOINCREMENT

Currency

CURRENCY, MONEY

Date/Time

DATETIME, DATE, TIME, TIMESTAMP

Number (Double)

DOUBLE, FLOAT, FLOAT8, IEEEDOUBLE, NUMBER, NUMERIC

Number (Long Integer)

LONG, INT, INTEGER, INTEGER4

OLE Object

LONGBINARY, GENERAL, OLEOBJECT

Memo

LONGTEXT, LONGCHAR, MEMO, NOTE

Number (Single)

SINGLE, FLOAT4, IEEESINGLE, REAL

Number (Integer)

SHORT, INTEGER2, SMALLINT

Text

TEXT, ALPHANUMERIC, CHAR, CHARACTER, STRING, VARCHAR

 

(Note: If CHAR or CHARACTER is used, a fixed-length text field is established; this is the only way a fixed-length text field can be defined. In the Access UI, Text fields are always variable-length and there is no way to specify otherwise there.)

 

size

The field size in characters (Text fields only). If size is omitted for a Text field, 255 is the default.

NOT NULL

Specifies that the field may not contain NULL values (an entry is required)

single-field CONSTRAINT clause

 

This clause has the following syntax:

 

CONSTRAINT constraint-name {PRIMARY KEY | UNIQUE | NOT NULL |

REFERENCES foreigntable [(foreignfield1, foreignfield2)]}

 

If PRIMARY KEY or UNIQUE is specified, an index of that type is established for this field. NOT NULL can either be specified as a named constraint or as a stand-alone clause (as seen above). The REFERENCES option establishes this field as foreign key, related to the primary key in another table.

multiple-field CONSTRAINT clause

 

This clause has the following syntax:

 

CONSTRAINT name {PRIMARY KEY (primary1[, primary2 [, ...]]) |

UNIQUE (unique1[, unique2 [, ...]]) |

NOT NULL (notnull1[, notnull2 [, ...]]) |

FOREIGN KEY (ref1[, ref2 [, ...]])

REFERENCES foreigntable [(foreignfield1 [, foreignfield2 [, ...]])]}

 

 

Example 46:

Create a new table called US_CUSTOMERS, which has the same structure as the existing Customers table.

 

CREATE TABLE US_CUSTOMERS

(CustomerID TEXT(5) CONSTRAINT PrimaryKey PRIMARY KEY,

CompanyName TEXT(40) NOT NULL,

ContactName TEXT(30),

ContactTitle TEXT(30),

Address TEXT(60),

City TEXT(15),

Region TEXT(15),

PostalCode TEXT(10),

Country TEXT(15),

Phone TEXT(24),

Fax TEXT(24))

 

If you switch over to the Tables tab, you'll see that US_CUSTOMERS has been added to the list of tables.

 

 

If you click the design button, you'll see how the fields have been set up based upon what has been coded in the CREATE TABLE statement. Note that the CustomerID field has been designated as the primary key and that by specifying NOT NULL for CompanyName, the Required property is set to "Yes".

 

 

 

Example 47:

Populate the US_CUSTOMERS table with data from the Customers table. Include only those rows for which Country is "USA".

 

INSERT INTO US_CUSTOMERS (CustomerID,

CompanyName,

ContactName,

ContactTitle,

Address,

City,

Region,

PostalCode,

Country,

Phone,

Fax)

SELECT CustomerID,

CompanyName,

ContactName,

ContactTitle,

Address,

City,

Region,

PostalCode,

Country,

Phone,

Fax

FROM Customers

WHERE Country = 'USA'

 

Check your results with a SELECT statement:

 

SELECT * FROM US_CUSTOMERS

 

 

Note: Although it is a "best practice" to specify the column names on both the INSERT part and the SELECT part of the query above, in the case where ALL fields from the source table will be inserted into the target table, you could get away with a shortened form of this query, as follows:

 

INSERT INTO US_CUSTOMERS

SELECT *

FROM Customers

WHERE Country = 'USA'

 

 

Changing the Table Structure

 

Adding a Column

 

Example 48:

Add a one-character field called CUSTOMER_TYPE to the US_CUSTOMERS table.

 

ALTER TABLE Customers

ADD RG_CODE TEXT(1);

 

Verify your results by looking at the US_CUSTOMERS table in design view:

 

 

 

To populate the new column in Access, you can an UPDATE statement. In our example, we want to set the RG_CODE to "W" for states on the west coast (California, Oregon, or Washington). The query is:

 

UPDATE Customers SET RG_CODE = 'W'

WHERE Region IN ('CA', 'OR', 'WA')

 

Verify the results with a SELECT statement:

 

SELECT CustomerID, CompanyName, Region, RG_CODE

FROM US_CUSTOMERS

 

 

Changing a Column Definition

 

In Access, you cannot use the ALTER TABLE statement to change the size or data type of a column. To do that you must create a new table that duplicates the original table but has the new column definition. You can then copy the data from the old table to the new table (using the SQL INSERT statement), delete the original table, and rename the new table to the old name. If the old table has relationships with other tables, those relationships must be deleted before you can delete the old table. Once the new table is in place, the relationships with the other tables can be re-established.

 

Some database systems, such as Oracle, let you change a column definition with the MODIFY clause of the ALTER TABLE statement. The following is acceptable in Oracle (but not Access):

 

ALTER TABLE US_CUSTOMER

MODIFY Address VARCHAR2(75);

 

Note: In Oracle, a variable length text field is specified with the keyword VARCHAR2.

 

Deleting a Column

 

Example 49:

Drop the Fax column from the US_CUSTOMERS table.

 

ALTER TABLE US_CUSTOMERS

DROP COLUMN Fax

Verify the results by looking at the US_CUSTOMERS table in design view.

 

DROP COLUMN is not supported by all database systems (such as Oracle). To accomplish this in a system that does not support DROP COLUMN, the following four steps would be necessary:

1. create new table, leaving out the column to be dropped

2. copy the other columns over from the new table

3. drop the old table

4. rename the new table to the old table name.

 

Dropping and Adding Constraints

 

The ALTER TABLE statement can also be used to drop a constraint from or add a constraint to an existing field in a table. In the next two exercises, we will drop the primary key constraint from the US_CUSTOMERS table, then add it back.

 

Example 50:

Drop the primary key constraint from the US_CUSTOMERS table. (Recall from the CREATE TABLE statement that we named that constraint PrimaryKey.)

 

ALTER TABLE US_CUSTOMERS

DROP CONSTRAINT PrimaryKey

 

Verify your results by looking at the US_CUSTOMERS table in Design View. Note that the Primary Key designation is gone.

 

Example 51:

Add the primary key constraint back to the US_CUSTOMERS table.

 

ALTER TABLE US_CUSTOMERS

ADD CONSTRAINT PrimaryKey PRIMARY KEY(CustomerID)

 

Verify your results by looking at the US_CUSTOMERS table in Design View. Note that the Primary Key designation is back.

 

Deleting a Table

 

Example 52:

Get rid of the US_CUSTOMERS table.

 

DROP TABLE US_CUSTOMERS

 

Verify your results by looking at the Tables tab of the database. Note that US_CUSTOMERS is gone.

 

It goes without saying that you should be VERY CAREFUL when dropping a table, or for that matter, when deleting data. Make sure you have a backup.

 

Creating a Database Structure from Scratch

 

This last example shows you how you can generate an entire database structure using CREATE TABLE statements. This exercise has you build your own version of the BIBLIO.MDB database that comes with both Access and VB. (If you do not have BIBLIO.MDB, you can download it here.)

 

·         On your hard disk, locate BIBLIO.MDB and open it.

 

·         Examine the table structures in the tables' design view.

 

·         Go to Tools -> Relationships and examine the ways in which the tables are related.

 

·         Close the database (but leave Access open)

 

·         Go to File -> New Database, and select a blank database

 

·         When asked to name the new database, call it MYBIBLIO.MDB

 

·         In SQL view, enter the following four CREATE TABLE queries:

 

CREATE TABLE Authors

(Au_ID AUTOINCREMENT CONSTRAINT Au_ID_PK PRIMARY KEY,

Author TEXT(50),

[Year Born] SHORT);

 

CREATE TABLE Publishers

(PubID AUTOINCREMENT CONSTRAINT PubID_PK PRIMARY KEY,

Name TEXT(50),

[Company Name] TEXT(255),

Address TEXT(50),

City TEXT(20),

State TEXT(10),

Zip TEXT(15),

Telephone TEXT(15),

Fax TEXT(15),

Comments MEMO);

 

CREATE TABLE Titles

(Title TEXT(255),

[Year Published] SHORT,

ISBN TEXT(20) CONSTRAINT ISBN_PK PRIMARY KEY,

PubID LONG CONSTRAINT PubID_FK REFERENCES Publishers(PubID),

Description TEXT(50),

Notes TEXT(50),

Subject TEXT(50),

Comments MEMO);

 

CREATE TABLE [Title Author]

(ISBN TEXT(20) CONSTRAINT ISBN_FK REFERENCES Titles(ISBN),

Au_ID LONG CONSTRAINT Au_ID_FK REFERENCES Authors(Au_ID),

CONSTRAINT TA_PK PRIMARY KEY(ISBN, Au_ID));

 

 

·         Examine your results in the tables' design view and in Tools -> Relationships.

 

If you enjoyed this post, subscribe for updates (it's free)

thanks

thanks

Introduction to SQL

Very good, I have sat and worked through all of the examples, I was very impressed with how comprehensive and easy to understand this was.

***However** *

I Think there is a mistake on Example 48, I know I new to SQL, but I am pretty sure that,

"Example 48:

Add a one-character field called CUSTOMER_TYPE to the US_CUSTOMERS table.

ALTER TABLE Customers

ADD RG_CODE TEXT(1);"

Should be

ALTER TABLE US_CUSTOMERS
ADD RG_CODE TEXT(1);

I really like you site and I am a genuine user, I am also very pleased with the results.

Thanks for all the help, continue the good work

Andy

Tnat/s good manual, simple

Tnat/s good manual, simple for understanding, even in fact that my knowledge of english is quite poor.

Probably the best tutorial

Probably the best tutorial I've seen around regarding this topic.

database

uhmm can u please give me some codes about
codes for finding the sum of database fields then the answer will display on label of form in vb6.0 please
i need idea.. from all of u..

wow thanks my friend!

wow thanks my friend! appreciated

LIKE statement

Hello,

This is very good tutorial. Thanks

I have created several tables in Access. I use VB6 to manipulate these tables using SQL statements.

The LIKE statement is not working, here is the SQL statement, please tell me what is wrong with it:

rsMyRS.Open "SELECT * FROM house WHERE price LIKE '*'", myDatabase

Thanks
Aiman

recordset.open "Select * From

recordset.open "Select * From ID where ID like '" & "%" & Text1.Text & "%" & "' ",Database

I used this code if you want to select from textbox where firt and last text don't know

This is my experiment

dude, this is my experiment....

i dont know if it is correct or not....

i use the like statement like this,

example code

recordset.open "Select * From ID where ID like '" & text1.text & "' ",Database

-------------------------------------------------------------------------------------------------

try this and if it is error ask this site....

ehehe

Done!

Don't use the '*' character.

Use the '%' instead. So:

rsMyRS.Open "SELECT * FROM house WHERE price LIKE '%'", myDatabase

ChrisGT7

SQL connection

I have designed a calculator that would be calculating students GPAs, and i want the calculator to be saving using Access db with an SQL . Please i want someone to give me a step by step process od doing it........ my E-mail Address: otorok@yahoo.com. thanks

Error?

Hi, I think you have made a mistake. The line item total shouldn't be :
 Format$(UnitPrice * Quantity * (1 + Discount)

Currently this doesn't discount the prices at all; it actually raises them! Instead, it should be :
Format$(UnitPrice * Quantity * (1 - Discount)

I don't know if this was done on purpose (I don't know why it would be..), so I'm just putting it out there.

Thanks you for your detail explanation

Dear Sir

Thanks you so much for detail explanation for writing SQL statement in ACCESS.

It would be most appreciated if you also explain about detail explanation for writing micro in ACCESS.

Thanks

its very good tutorial..thanx

its very good tutorial..thanx a lot

Thank you so much for your

Thank you so much for your SQL Tutorial.... Really useful..... Why the rain in comming regularly...to help people of world.... because
you people...helping others.... so God satisfied and sending the rain... Thank you....

Great ....

Sir,
This is a great service .....
May god bless you and your family...
Thank you very much.
Ragards

connectivity of vb 6 to sql 2005

I need the tutorial for connectivity of vb 6.0 with SQL server 2005. And step by step process of Adding, Updating the database or Deleting the database value or values on the button click on the VB form. Please Help ..............

awesome!!

this is a great help for us..thanks a lot!!

awesome!!

this is a great help for us..thanks a lot!!

an man??!

k kadacul man sadi!!

The Best!

Hey, thanks it was a very good compilation.
It is very beneficial to us instructors. Thanks..

Encrypting passwords

Hi co-members! can any of you help me with a way in which i can encrypt passwords stored in database so that some one cant get the password even if he/she manages to open the database that contains the passwords?

dfgdfhyrtgnhjgfffffffffffffff

dfgdfhyrtgnhjgfffffffffffffffffffnhj gggggggggggggggggggggggggggghhhhhhhhhhhhhhhgfgfgfgfgfgfgfgfgfhgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfhhhhhhhhhhhhhhhhfggggggggggggggggggggggggggggggggggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhdffffffffffffffffffffffffgfhfhgfhhhhhhhhhhhhhhhhhfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgffffffffffffffffffffffffffffffffffffffffffffffnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnndc gftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgftgfthhhhhhhhhhhhhh

stupid fellow

stupid fellow

SQL Query

How to us SQL query in VB6,
In
DataEnvironment > Connection > Command > Properties > SQL Statements.

Please tell me how to fetch text box or combobox values in the SQL statements.
I have used this query but it is not working properly
select * from TABLENAME where FIELD = '"& Textbox.text &"'

Thanks in advance,
Rohit

My E-mail ID is - rohitsonar@hotmail.com

Joining text box for search in sql

Try this
Dim Find As String
Find="Select * from TABLENAME where TABLENAME.FIELD = " & "'" & Text1.Text & "'"
Data1.RecordSource = Find
Data1.Refresh

Thanks!

Just what I need! Tnx so much :-)

Just what I needed

Very Good! Somehow, you've kept it very simple but very informative.

tnx

very helpful =)

about sql and vb

how can i add sql DB in VB?

VERY HELPFUL..

I can actually learn it myself. But also, I still need to ask my prof for further explanation. Though it really REALLY HELPED ME A LOT! You're now my idol man! I'll read the rest. :) God bless and keep sharing what you know.

Greatest Coading

It is nice tetorial for SQL in VB its gives a strong Back end for Storages Data thank you

Introduction to SQL (Structured Query Language)

Thank you, this is one of the best information I have seen about SQL.
I found explanations which are nor mentionned in a book I considered as a good one (The Practical SQL HandbooK - Bowman, Emerson and Darnovsky)
I have been playing around with VBA since excel 95 but because of problems with Excel 2007, I decided one month agoto step over and use VB6.0 and Access (Only the database, not the other functions...)
I am writing a school management application...
Actually, I'd like to use MySQL but I don't know where to start...
Thanks a lot again

Cheers
Bernard

Report

This tutorial is very useful to me....its allobrate the information correctly............i have request to provide the sql2000 and vb6 sw ..and coding and explanation for same project

It was nice but one still something missing

Hello Everyone out there, the above tutorial is fabulous but I found something still missing. I was looking for example:

If the NEW ORDER has been placed and if there 1000 items which are of same catagory and If the customer orders only for 200 items then to my amazement not find in this vast SQL information that how the one SELECT or DELETE from the STOCK only 200 items out of 1000 items to place the order. I know it not very complicated but I really dont have idea about it as Im newbie to SQL but was expecting the query on this website but I found hopeless myself. Anyhow if the authors of this website are reading these comments regularly then please also add the said idea as well. Thank you all.

SELECT TOP 200 FROM

SELECT TOP 200 FROM WHERE
or
DELETE TOP 200 FROM WHERE

nice, your pdf link goes to

nice, your pdf link goes to a lets say, not so nice to my pc site.

great!really helpful

i like this tutorial....very informtive...
think with this help
i will be able to pass my vb subject!!!
thanks a lot!!!

Thanks

Thank you for such an informative and handy tutorial.

This is called "Exact" &

This is called "Exact" & purely "Compact" teaching. Hmm!

Brilliant!

Thanks guys, this is really helpful!

hi

This is a AWESOME tutorial.

really great.

Thanks

Excellent! Thanks a lot............

Excelent

Great jog and helps the SQL beginners a lot.

Tutorial Lacks Something

This tutorial is lacking.. why is it all TEXT? Please update this with NUMBER or DATE fields..

superb man best topic i have

superb man best topic i have ever seeen coooooooooooooooooooooooooooooool

HTML - change your H6 elements

Nice content, but you need HTML formatting help. An "H6" element is for a 6th-level heading, and it uses a small font by default.

LIKE function

question: How do use LIKE function in SQL statement if the string you are trying to locate contains the character: '
example: SELECT * FROM Table WHERE Field LIKE '%O'Neil%'

it is giving me a syntax error, missing operator.

how do i solve this.

Thanks!

great!

the page was very helpful and easy to understand. thank you - good job!

good

good

gfgfgfgfgfgfgfgfgfgfgfgfgfgfg

gfgfgfgfgfgfgfgfgfgfgfgfgfgfgf

What a marvelous helper

I am so happy for the creator or develoers of this site whom i find it very interested and very helpful...I do hope that God will give you strength to continue on this work...You light your world to the people and God will even give you more light...and you will get smarter as days go....

Just From A Tongan Crusader For Christ

Excellent. It is a pity that

Excellent.
It is a pity that this was not around when I was learning SQL

Rob