Chapter
15
Chapter 15
Updating
Databases with SQL
In today's lesson, you learn about the SQL Data
Manipulation Language (DML) keywords you can use to update and modify data in existing
tables. Although most of the time you use Visual Basic data entry forms and Visual Basic
program code to perform data table updates, there are often times when it is more
desirable to use SQL statements to update your data tables.
When you complete the examples in this chapter, you
will be able to:
- Alter the contents of existing tables using the UPDATE
statement.
- Add new rows to existing tables with the INSERT
INTO statement.
- Append rows from one table to another using the INSERT
INTO_FROM clause.
- Copy one or more rows from an existing table to a new
table using the SELECT_INTO keywords.
- Remove selected rows from a table using the DELETE_FROM
clause.
NOTE: Throughout this chapter, you use the SQL-VB5
program to create and run SQL scripts. The lesson on Day 13, "Creating Databases with
SQL," contains a short tutorial on where to locate the SQL-VB5 program and
how to use it. If you have not worked through the lesson on Day 13 yet, now is a good time
to review at least the first half of that chapter.
Data
Manipulation SQL Keywords
The Data Manipulation Language (DML) SQL keywords
are used to add new data to existing tables, edit existing table data, append data from
one table to another, copy data from one table to an entirely new table, and delete data
rows from existing tables.
Most of the time, your Visual Basic programs use
data-entry screens to perform these tasks. However, sometimes the DML keywords come in
handy. In some back-end database systems, these SQL keywords are the only way you can add,
edit, or delete data from tables. At other times, these SQL keywords give you the power to
produce updates to large tables with very few lines of code and in a relatively short
amount of time.
Also, many times you might need to select a small
subset of data from your tables for a report or a graphic display. Instead of creating
Dynaset views of existing tables, you might want to create a frozen Snapshot of the data
to use for this purpose. What you need to do is copy some records from an existing table
into a new table for use in reporting and displays. SQL DML keywords can help create these
select tables quickly without extensive Visual Basic code.
Another example of using SQL DML keywords is when
you want to append a set of records from one table to another. Instead of writing Visual
Basic code routines that read a record from one table and then write it to another, you
can use SQL DML keywords to perform the table update--many times with just one line of SQL
code.
Finally, SQL DML keywords allow you to quickly
delete entire tables or subsets of data in a single SQL statement. This reduces the amount
of Visual Basic code you need to write and also greatly speeds the processing in most
cases.
Adding Rows
with the INSERT Statement
The INSERT statement is used to insert
values into data tables. You can use the INSERT statement to populate data tables
automatically--without the need for data-entry screens. Also, you can perform this
automatic data entry using very little Visual Basic code. Why Use INSERT Statements? Even
though you most often perform data entry using Visual Basic-coded data-entry screens tied
to Visual Basic data controls, there are times when using the INSERT statement
can prove more efficient. An excellent example of using INSERT statements is the
installation of a new database system. Often, several data tables need to be populated
with default values before people can start using a system. You can use the INSERT
statement to perform the initial data load.
Another use for the INSERT statement is in
converting data from one database to another. Often, you can use INSERT
statements to load existing data in one format into your newly designed relational
database.
Finally, you can use INSERT statements to
quickly add data to tables that would be too tedious to enter using data-entry screens.
Using the INSERT INTO Statement The basic form of the INSERT statement is
INSERT INTO TableName(field1, field2)
VALUES (value1, value2); |
NOTE: INSERT and INSERT INTO statements are often used
interchangeably. For the most part, this guide uses the latter term.
The INSERT SQL statement has three parts.
The TableName identifies the table that you want to update. The (field1, field2)
part of the statement identifies the columns into which you add data. The (value1,
value2) part of the statement identifies the exact values you add to the
fields you identified. You can name as few or as many fields as you like in the field
portion of the statement. However, you must supply a list of values that has the same
number of values and the same data type as those identified in the field portion of the
statement. Also, you must list the values in the same order as the fields. The first value
is placed in the first field, the second value in the second field, and so on.
Let's use SQL-VB5 to create a working
example of the INSERT statement. Open a new .SQV script called SQLVB05.SQV
using the File | New command from the main menu. Enter the script shown in Listing 15.1,
save it, and execute it using the File | Run menu option. Refer to Figure 15.1 to compare
your results.
Listing 15.1.
Testing the INSERT INTO keyword.
//
// sqlvb05.sqv - Testing the INSERT INTO keyword
//
// create a new database
dbMake sqlvb05.mdb;
// create a new table
CREATE TABLE JobTitles
(JobID TEXT(5) CONSTRAINT PKJobTitle PRIMARY KEY,
JobName TEXT(20),
JobDesc MEMO
);
// insert some data
INSERT INTO JobTitles(JobID, JobName, JobDesc) VALUES
(`J001',
`President',
`Presides over the company'
);
INSERT INTO JobTitles(JobID, JobName, JobDesc) VALUES
(`J002',
`Vice President',
`Does what the President tells him to do'
);
// display results
SELECT * FROM JobTitles;
// eof |
Figure 15.1. The results
of the INSERT INTO statement.
Notice that you must use a separate INSERT INTO statement for each row you want
to add to the table. If you wanted to add 10 more job descriptions to the JobTitles table,
you would need to add 10 more INSERT INTO statements to the script.
Also, because you defined the JobsTitles.JobID
column as the primary key, you are required to fill that field with unique, non-null data
each time you execute the INSERT INTO statement. If you provide a null value or
leave the JobsTitles.JobID field out of the INSERT INTO statement, you get a
database error message.
If you use a COUNTER data type field in your table,
you can't include that in the field list of the INSERT INTO statement. Visual
Basic and the SQL engine fill the COUNTER field with an appropriate value. Also, you do
not have to add data to every column in the row. If there are fields in the data table
that are not required and that can be left null, you can simply omit them from the INSERT
INTO statement. The code example in Listing 15.2 illustrates these last two points.
Use SQL-VB5 to edit the SQLVB05.SQV script to match the one in Listing
15.2. Save and execute the script. Check your results against those in Figure 15.2.
Listing 15.2.
Handling COUNTER and blank fields in INSERT statements.
//
// sqlvb05.sqv - Testing the INSERT INTO keyword
//
// create a new database
dbMake sqlvb05.mdb;
// create a new table
CREATE TABLE JobTitles
(JobCounter COUNTER,
JobID TEXT(5) CONSTRAINT PKJobTitle PRIMARY KEY,
JobName TEXT(20),
JobPay CURRENCY,
JobDesc MEMO
);
// insert some data
INSERT INTO JobTitles (JobID, JobName, JobDesc, JobPay) VALUES
(`J001',
`President',
`Presides over the company',
`50000'
);
INSERT INTO JobTitles (JobID, JobName, JobDesc, JobPay) VALUES
(`J002',
`Vice President',
`Does what the President tells him to do',
`40000'
);
INSERT INTO JobTitles (JobID, JobPay, JobName) VALUES
(`J003',
`35000',
`Chief Engineer'
);
// display results
SELECT * FROM JobTitles;
// eof |
Notice that the JobTitles.JobCounter column was automatically populated by Visual Basic.
Also, you can see that the JobTitles.JobDesc column was left blank for the third record in
the table.
Figure 15.2. The results
of using INSERT INTO with COUNTER and optional fields.
Two other interesting things about the INSERT INTO statement are illustrated in
the code example in Listing 15.2. Notice that the values for the JobTitles.JobPay column
were surrounded by quotation marks even though the data type is CURRENCY. When you use the
INSERT INTO statement, all values must be surrounded by quotation marks. SQL and
Visual Basic handle any type conversions needed to insert the values into the identified
fields.
The second interesting thing to note in Listing 15.2
is the order in which columns are listed in the INSERT INTO statements. If you
look at each of the statements, you see that the JobTitles.JobPay column appears in
different places within the field list. When you use the INSERT INTO statement,
you can list the columns in any order. You only need to make sure that you list the values
to be inserted in the same order in which you list the columns.
You have learned how to use the INSERT INTO
statement to add individual rows to a table. This is commonly called a single-record
insert. In the next section, you learn about a more powerful version of the INSERT
INTO statement, commonly called an append query.
Creating
Append Queries with INSERT INTO_FROM
The INSERT INTO_FROM version of the INSERT
statement allows you to insert multiple records from one table into another table. This
multirecord version of INSERT INTO is called an append query because it enables
you to append rows from one table to the end of another table. As long as the two tables
you are working with have fields with the same name, you can use the INSERT INTO_FROM
statement.
The basic format of the INSERT INTO_FROM
statement is
INSERT INTO TargetTable SELECT field1,
field2 FROM SourceTable; |
There are three important parts of the INSERT
INTO_FROM statement. The first part is the TargetTable. This is the table that is
updated by the statement. The second part is SELECT fields. This is a list of the
fields that are updated in the TargetTable. These are also the fields that are supplied by
the third part of the statement--the SourceTable. As you can see, the INSERT INTO_FROM
statement is really just a SELECT_FROM query with an INSERT INTO TargetTable
in front of it.
Now, let's update the SQLVB05.SQV to
provide an example of the INSERT INTO_FROM statement. First, use SQL-VB5
to load and edit the SQLVB05.SQV script. Make changes to the script so that it
matches Listing 15.3. Save the script and run it. Check your results against those shown
in Figure 15.3.
Listing
15.3. Using the INSERT INTO_FROM statement.
//
// sqlvb05.sqv - Testing the INSERT INTO keyword
//
// create a new database
dbMake sqlvb05.mdb;
// create a new table
CREATE TABLE JobTitles
(JobCounter COUNTER,
JobID TEXT(5) CONSTRAINT PKJobTitle PRIMARY KEY,
JobName TEXT(20),
JobPay CURRENCY,
JobDesc MEMO
);
// insert some data
INSERT INTO JobTitles (JobID, JobName, JobDesc, JobPay) VALUES
(`J001',
`President',
`Presides over the company',
`50000'
);
INSERT INTO JobTitles (JobID, JobName, JobDesc, JobPay) VALUES
(`J002',
`Vice President',
`Does what the President tells him to do',
`40000'
);
INSERT INTO JobTitles (JobID, JobPay, JobName) VALUES
(`J003',
`35000',
`Chief Engineer'
);
// create a second table to hold some of the info from JobTitles
CREATE TABLE JobReport
(JobID TEXT(5) CONSTRAINT PKJobReport PRIMARY KEY,
JobName TEXT(20),
JobDesc MEMO,
DeptID TEXT(5)
);
// now append records from JobTitles into JobReport
INSERT INTO JobReport
SELECT JobID, JobName, JobDesc FROM JobTitles;
// display results
SELECT * FROM JobTitles;
SELECT * FROM JobReport;
// eof |
Figure 15.3. The results
of the INSERT INTO_FROM statement.
NOTE: You might have noticed in Listing 15.3
that you created two indexes, each on an identical column name, but you gave the two
indexes different names. SQL does not allow you to use the same name on different indexes,
even if they refer to different tables. Indexes appear as independent data objects in a
Microsoft Access database. Each object must have a unique name.
Notice that the INSERT INTO_FROM statement
lists only those fields that are present in both tables. You need to list the columns by
name in this example because the JobReport table does not contain all the fields that the
JobTitles table contains. If both tables were an exact match, you could use the asterisk
wildcard (*) character in the SELECT clause. For example, if JobTitles
and JobReport shared all the same column names, you could use the following SQL statement
to append data from one to the other:
INSERT INTO JobReport SELECT * FROM
JobTitles; |
You can also use the INSERT INTO statement
to append rows to tables in another database. You accomplish this by adding an IN
clause to the first part of the statement. For example, you can add rows from the
JobTitles table in SQLVB05.MDB to a similar table in another database called SQLVB05B.MDB.
The syntax for the IN clause of an INSERT INTO_FROM statement is
IN "DatabaseFileName" "DatabaseFormat"
DatabaseFileName is the complete database filename
including the drive identifier and the path name of the destination (or external)
database. DatabaseFormat is the name of the database format of the destination database,
such as FoxPro, dBASE, Paradox, and so on. For example, if you want to update TableOne in
the external database called EXTERNAL.MDB on drive C in the directory
called DB, you would use the following IN clause for the SELECT INTO
statement:
SELECT INTO TableOne IN
"c:\db\external.mdb" "access" |
Listing 15.4 shows how this is done using a real set
of database files. Use SQL-VB5 to load and edit SQLVB05.SQV to match the
modifications outlined in Listing 15.4. Save the script and execute it. Your results
should look similar to those in Figure 15.4.
Listing
15.4. Adding the IN clause.
//
// sqlvb05.sqv - Testing the INSERT INTO keyword
//
// create sqlvgb05b database
dbMake sqlvb05b.mdb;
// make a table
CREATE TABLE OtherTitles
(JobCounter COUNTER,
JobID TEXT(5) CONSTRAINT PKJobTitle PRIMARY KEY,
JobName TEXT(20),
JobPay CURRENCY,
JobDesc MEMO
);
// insert some rows
INSERT INTO OtherTitles (JobID, JobName, JobDesc, JobPay) VALUES
(`J004',
`Line Foreman',
`Supervises production line',
`30000'
);
INSERT INTO OtherTitles (JobID, JobName, JobDesc, JobPay) VALUES
(`J005',
`Line Worker',
`Does what the Line Foreman tells him to do',
`25000'
);
// show results
SELECT * FROM OtherTitles;
// now close this database
dbClose;
// ********************************************************
// create a new database
dbMake sqlvb05.mdb;
// create a new table
CREATE TABLE JobTitles
(JobCounter COUNTER,
JobID TEXT(5) CONSTRAINT PKJobTitle PRIMARY KEY,
JobName TEXT(20),
JobPay CURRENCY,
JobDesc MEMO
);
// insert some data
INSERT INTO JobTitles (JobID, JobName, JobDesc, JobPay) VALUES
(`J001',
`President',
`Presides over the company',
`50000'
);
INSERT INTO JobTitles (JobID, JobName, JobDesc, JobPay) VALUES
(`J002',
`Vice President',
`Does what the President tells him to do',
`40000'
);
INSERT INTO JobTitles (JobID, JobPay, JobName) VALUES
(`J003',
`35000',
`Chief Engineer'
);
// create a second table to hold some of the info from JobTitles
CREATE TABLE JobReport
(JobID TEXT(5) CONSTRAINT PKJobReport PRIMARY KEY,
JobName TEXT(20),
JobDesc MEMO
);
// now append records from JobTitles into JobReport
INSERT INTO JobReport
SELECT JobID, JobName, JobDesc FROM JobTitles;
// display results
SELECT * FROM JobTitles;
SELECT * FROM JobReport;
// now append data from one database to another
INSERT INTO OtherTitles IN "sqlvb05b.mdb" "Access"
SELECT JobID, JobName, JobDesc, JobPay FROM JobTitles;
// close this db
dbClose;
// open other db
dbOpen sqlvb05b.mdb
// show updated table
SELECT * FROM OtherTitles;
// eof |
Figure 15.4. The results
of the INSERT INTO_FROM statement with the IN clause.
The script in Listing 15.4 first creates a database with a single table (OtherTitles) that
has two records in the table. Then the script displays the table for a moment before the
database is closed. Notice that the records in the table have OtherTitles.JobCounter
values of 1 and 2. Then the script creates the JobTitles table in
another database and populates that table with three records. Other tables are populated
(this was done in previous examples), and eventually the JobTitles table is displayed. The
three records have JobTitles.JobCounter values of 1, 2, and 3.
Finally, the INSERT INTO_FROM_IN statement is executed to update the external
data table. Then the external table is opened so that you can view the results.
Now look at the OtherTitles.JobCounter values. What
has happened? When you append COUNTER data fields to another table, the new records are
renumbered. This ensures unique counter values in the table. If you want to retain the old
numbers, you can include the COUNTER field in your INSERT INTO list. To
illustrate this, add the JobCounter column name to the field list in the INSERT INTO
statement that updated the external table (see Figure 15.5). Now execute the script again
to see the results.
Figure 15.5. The results
of the INSERT INTO_FROM_IN with an updated counter column.
As you can see in Figure 15.5, you now have duplicate COUNTER values in your table. This
can lead to data integrity problems if you are using the COUNTER data type as a guaranteed
unique value. You should be careful when you use INSERT INTO statements that
contain COUNTER data type columns.
WARNING: The Microsoft Visual Basic
documentation for the behavior of INSERT INTO with COUNTER data types states that
duplicate counter values are not appended to the destination table. This is not correct.
The only time duplicates are not included in the destination tables is when the COUNTER
data type column is defined as the primary key.
We should point out here that if you attempt to
append records to a table that has a duplicate primary key value, the new record is not
appended to the table--and you do not receive an error message! If you edit the SQLVB05.SQV
script to renumber the OtherTitles.JobID values to J001 and J002, you
see a different set of results when you run the script. Figure 15.6 shows what you get
when you attempt to update duplicate primary key rows.
Figure 15.6. The results
of attempting to append duplicate primary key rows.
The fact that SQL does not append records with a duplicate key can be used as an
advantage. You can easily merge two tables that contain overlapping data and get a single
result set that does not contain duplicates. Anyone who has worked with mailing lists can
find a use for this feature of the INSERT INTO statement.
Now that you know how to insert rows into tables,
it's time to learn how you can update existing rows using the UPDATE_SET
statement.
Creating
UPDATE Queries with the UPDATE_SET Statement
The UPDATE_SET statement enables you to
update a large amount of data in one or more tables very quickly with very little coding.
You use the UPDATE_SET statement to modify data already on file in a data table.
The advantage of the UPDATE_SET statement is that you can use a single statement
to modify multiple rows in the table.
For example, assume that you have a table of 500
employees. You are told by the Human Resources department that all employees are to be
given a 17.5 percent increase in their pay starting immediately (wouldn't it be nice?).
You could write a Visual Basic program that opens the table, reads each record, computes
the new salary, stores the updated record, and then goes back to read the next record.
Your code would look something like the pseudocode sample in Listing 15.5.
NOTE: Listing 15.5 is not a real Visual Basic
program; it is just a set of statements that read like program code. Such pseudocode is
often used by programmers to plan out programs without having to deal with the details of
a particular programming language. Another benefit of using pseudocode to plan programs is
that people do not need to know a particular programming language to be able to understand
the example.
Listing
15.5. Sample code for record-oriented updates.
OPEN EmpDatabase
OPEN EmpTable
DO UNTIL END-OF-FILE (EmpTable)
READ EmpTable RECORD
EmpTable.EmpSalary = EmpTable.EmpSalary * 1.175
WRITE EmpTable RECORD
END DO
CLOSE EmpTable
CLOSE EmpDatabase |
This is a relatively simple process, but--depending on the size of the data table and the
speed of your workstation or the database server--this kind of table update could take
quite a bit of time. You can use the SQL UPDATE statement to perform the same
task.
OPEN database
UPDATE EmpTable SET EmpSalary = EmpSalary * 1.175
CLOSE database |
The preceding example shows how you can accomplish
the same task with less coding. Even better, this code runs much faster than the
walk-through loop shown in Listing 15.5, and this single line of code works for any number
of records in the set. Furthermore, if this statement is sent to a back-end database
server connected by ODBC and not processed by the local workstation, you could see an even
greater increase in processing speed for your program.
Let's start a new program that illustrates the UPDATE_SET
statement. Use SQL-VB5 to create a new script file called SQLVB06.SQV
and enter the commands in Listing 15.6. After you save the script, execute it and check
your results against those in Figure 15.7.
Listing
15.6. Using the UPDATE_SET statement.
Figure 15.7. The results
of using the UPDATE_SET statement.
NOTE: Notice that you did not include the
column names in the INSERT INTO statements in this example. As long as you are
supplying all the column values for a table, in the same order that they appear in the
physical layout, you can omit the column names from the statement.
As you can see in Figure 15.7, all the records in
the table are updated by the UPDATE_SET statement. The SET statement
works for both numeric and character fields. It can contain any number of column updates,
too. For example, if you have a table that has three fields that need to be updated, you
can use the following SQL statement:
UPDATE MyTable SET
CustType="RETAIL",
CustDiscount=10,
CustDate=#01/15/96#;
You can also add a WHERE clause to the UPDATE
statement to limit the rows that are affected by the SET portion of the
statement. What if you want to give anyone whose salary is over $30,000 a 10 percent raise
and anyone whose salary is $30,000 or under a 15 percent raise? You could accomplish this
with two UPDATE_SET statements that each contain a WHERE clause. Use the
code in Listing 15.7 as a guide to modifying the SQLVB06.SQV script. Save your
changes and run the script. Check your results against Figure 15.8.
Listing
15.7. Adding the WHERE clause to the UPDATE statement.
//
// sqlvb06.sqv - testing the UPDATE ... SET statement
//
// create a database
dbMake sqlvb06.mdb;
// create a table
CREATE TABLE EmpTable
(EmpID TEXT(5) CONSTRAINT PKEmpTable PRIMARY KEY,
EmpName TEXT(30),
EmpSalary CURRENCY
);
// insert some data
INSERT INTO EmpTable VALUES
(`E001',
`Anderson, Shannon',
`35000'
);
INSERT INTO EmpTable VALUES
(`E002',
`Billings, Jesse',
`30000'
);
INSERT INTO EmpTable VALUES
(`E003',
`Caldwell, Dana',
`25000'
);
// show first result set
SELECT * FROM EmpTable AS FirstPass;
// now perform updates
UPDATE EmpTable SET EmpSalary = EmpSalary * 1.10
WHERE EmpSalary > 30000;
UPDATE empTable SET EmpSalary = EmpSalary * 1.15
WHERE EmpSalary <= 30000;
// show new results
SELECT * FROM EmpTable AS SecondPass;
// eof |
In Listing 15.7, you use the WHERE clause to isolate the records you want to
modify with the UPDATE_SET statement. The WHERE clause can be as simple
or as complicated as needed to meet the criteria. In other words, any WHERE
clause that is valid within the SELECT_FROM statement can be used as part of the UPDATE_SET
statement.
Figure 15.8. The results
of the UPDATE query with a WHERE clause.
Creating Make Table Queries Using the SELECT_INTO_FROM
Statement
The SELECT_INTO_FROM statement allows you
to create entirely new tables, complete with data from existing tables. This is called a
Make Table query because it enables you to make a new table. The difference between Make
Table queries and the CREATE TABLE statement is that you use the Make Table query
to copy both the table structure and the data within the table from an already existing
table. Because the Make Table query is really just a form of a SELECT statement,
you can use all the clauses valid for a SELECT statement when copying data
tables, including WHERE, ORDER BY, GROUP BY, and HAVING.
Make Table queries are excellent for making backup
copies of your data tables. You can also create static read-only tables for reporting and
reviewing purposes. For example, you can create a Make Table query that summarizes sales
for the period and save the results in a data table that can be accessed for reports and
on-screen displays. Now you can provide summary data to your users without giving them
access to the underlying transaction tables. This can improve overall processing speed and
help provide data security, too.
The basic form of the Make Table query is
SELECT field1, field2 INTO
DestinationTable FROM SourceTable; |
In the preceding example, the field1, field2
list contains the list of fields in the SourceTable that is copied to the
DestinationTable. If you want to copy all the columns from the source to the destination,
you can use the asterisk wildcard (*) character for the field list. Enter the SQL-VB5
script in Listing 15.8 as SQLVB07.SQV. Save and execute the script, and check
your on-screen results against those in Figure 15.9.
Listing
15.8. Testing Make Table queries.
//
// sqlvb07.sqv - Testing Make Table Queries
//
// create a database
dbMake sqlvb07.mdb;
// create a base table
CREATE TABLE BaseTable
(CustID TEXT(10) CONSTRAINT PKBaseTable PRIMARY KEY,
CustName TEXT(30),
CustBalance CURRENCY,
CustType TEXT(10),
Notes MEMO
);
// add some data
INSERT INTO BaseTable VALUES
(`CUST01',
`Willingham & Associates',
`300.65',
`RETAIL',
`This is a comment'
);
INSERT INTO BaseTable VALUES
(`CUST02',
`Parker & Parker',
`1000.29',
`WHOLESALE',
`This is another comment'
);
INSERT INTO BaseTable VALUES
(`CUST03',
`Anchor, Smith, & Hocking',
`575.25',
`RETAIL',
`This is the last comment'
);
// now make a new table from the old one
SELECT * INTO CopyTable FROM BaseTable;
// show results
SELECT * FROM BaseTable;
SELECT * FROM CopyTable;
// eof |
Figure 15.9. The results
of a simple Make Table query.
In Listing 15.8, you created a database with one table, populated the table with some test
data, and then executed a Make Table query that copied the table structure and contents to
a new table in the same database.
You can use the WHERE clause to limit the
rows copied to the new table. Modify SQLVB07.SQV to contain the new SELECT_INTO
statement and its corresponding SELECT_FROM, as shown in Listing 15.9. Save the
script and execute it. Your results should look similar to those shown in Figure 15.10.
Listing
15.9. Using the WHERE clause to limit Make Table queries.
//
// sqlvb07.sqv - Testing Make Table Queries
//
// create a database
dbMake sqlvb07.mdb;
// create a base table
CREATE TABLE BaseTable
(CustID TEXT(10) CONSTRAINT PKBaseTable PRIMARY KEY,
CustName TEXT(30),
CustBalance CURRENCY,
CustType TEXT(10),
Notes MEMO
);
// add some data
INSERT INTO BaseTable VALUES
(`CUST01',
`Willingham & Associates',
`300.65',
`RETAIL',
`This is a comment'
);
INSERT INTO BaseTable VALUES
(`CUST02',
`Parker & Parker',
`1000.29',
`WHOLESALE',
`This is another comment'
);
INSERT INTO BaseTable VALUES
(`CUST03',
`Anchor, Smith, & Hocking',
`575.25',
`RETAIL',
`This is the last comment'
);
// now make a new table from the old one
SELECT * INTO CopyTable FROM BaseTable;
// select just some of the records
SELECT * INTO RetailTable FROM BaseTable
WHERE CustType='RETAIL';
// show results
SELECT * FROM BaseTable;
SELECT * FROM CopyTable;
SELECT * FROM RetailTable;
// eof |
As you can see from Figure 15.10, only the rows with WHERE CustType =
`RETAIL' are copied to the new table.
You can also use the GROUP BY and HAVING
clauses to limit and summarize data before copying to a new table. Let's modify the SQLVB07.SQV
script to produce only one record for each customer type, with each new row containing the
customer type and total balance for that type. Let's also order the records in descending
order by customer balance. Let's rename the CustBalance field to Balance. The
modifications to SQLVB07.SQV are shown in Listing 15.10. Make your changes, save
and run the script, and compare your results to Figure 15.11.
Figure 15.10. Using the WHERE
clause to limit Make Table queries.
Listing 15.10. Using GROUP BY and HAVING to summarize data.
//
// sqlvb07.sqv - Testing Make Table Queries
//
// create a database
dbMake sqlvb07.mdb;
// create a base table
CREATE TABLE BaseTable
(CustID TEXT(10) CONSTRAINT PKBaseTable PRIMARY KEY,
CustName TEXT(30),
CustBalance CURRENCY,
CustType TEXT(10),
Notes MEMO
);
// add some data
INSERT INTO BaseTable VALUES
(`CUST01',
`Willingham & Associates',
`300.65',
`RETAIL',
`This is a comment'
);
INSERT INTO BaseTable VALUES
(`CUST02',
`Parker & Parker',
`1000.29',
`WHOLESALE',
`This is another comment'
);
INSERT INTO BaseTable VALUES
(`CUST03',
`Anchor, Smith, & Hocking',
`575.25',
`RETAIL',
`This is the last comment'
);
// now make a new table from the old one
SELECT * INTO CopyTable FROM BaseTable;
// select just some of the records
SELECT * INTO RetailTable FROM BaseTable
WHERE CustType='RETAIL';
// create a new summary table with fancy stuff added
SELECT CustType, SUM(CustBalance) AS Balance INTO SummaryTable
FROM BaseTable
GROUP BY CustType;
// show results
SELECT * FROM BaseTable;
SELECT * FROM CopyTable;
SELECT * FROM RetailTable;
SELECT * FROM SummaryTable;
// eof
|
Figure 15.11. Using GROUP
BY and HAVING to summarize data.
In all the examples so far, you have used the SELECT_INTO statement to copy
existing tables to another table within the database. You can also use SELECT_INTO
to copy an existing table to another database by adding the IN clause. You can
use this feature to copy entire data tables from one database to another, or to copy
portions of a database or data tables to another database for archiving or reporting
purposes.
For example, if you want to copy the entire
BaseTable you designed in the previous examples from SQLVB07.MDB to SQLVB07B.MDB,
you could use the following SELECT_INTO statement:
SELECT * INTO CopyTable IN
sqlvb07b.mdb FROM BaseTable; |
You can use all the WHERE, ORDER BY,
GROUP BY, HAVING, and AS clauses you desire when copying tables
from one database to another.
WARNING: When you copy tables using the SELECT_INTO
statement, none of the indexes or constraints are copied to the new table. This is an
important point. If you use SELECT_INTO to create tables that you want to use for
data entry, you need to reconstruct the indexes and constraints using CREATE INDEX
to add indexes and ALTER TABLE to add constraints.
Creating
Delete Table Queries Using DELETE_FROM
The final SQL statement you learn today is the DELETE_FROM
statement, commonly called the Delete Table query. Delete Table queries are used to remove
one or more records from a data table. The delete query can also be applied to a valid
view created using the JOIN keyword. Although it is not always efficient to use
the DELETE statement to remove a single record from a table, it can be very
effective to use the DELETE statement to remove several records from a table. In
fact, when you need to remove more than one record from a table or view, the DELETE
statement outperforms repeated uses of the Delete method in Visual Basic code.
In its most basic form, the DELETE
statement looks like this:
DELETE FROM TableName;
In the preceding example, TableName represents the
name of the base table from which you are deleting records. In this case, all records in
the table are removed using a single command. If you want to remove only some of the
records, you could add an SQL WHERE clause to limit the scope of the DELETE
action.
DELETE FROM TableName WHERE Field = value;
This example removes only the records that meet the
criteria established in the WHERE clause.
Now let's create some real DELETE
statements using SQL-VB. Start a new script file called SQLVB08.SQV, and
enter the script commands in Listing 15.11. Save the script and execute it. Check your
results against those shown in Figure 15.12.
Listing
15.11. Using the DELETE statement.
//
// sqlvb08.sqv - Testing DELETE statements
//
// create a new database
dbMake sqlvb08.mdb;
// create a table to work with
CREATE TABLE Table1
(RecID TEXT(10),
LastName TEXT(30),
FirstName TEXT(30),
RecType TEXT(5),
Amount CURRENCY,
LastPaid DATE
);
// add some records to work with
INSERT INTO Table1 VALUES
(`R01',
`Simmons',
`Chris',
`LOCAL',
`3000',
'12/15/95'
);
INSERT INTO Table1 VALUES
(`R02',
`Walters',
`Curtis',
`INTL',
`5000',
'11/30/95'
);
INSERT INTO Table1 VALUES
(`R03',
`Austin',
`Moro',
`INTL',
`4500',
'01/15/96'
);
// show loaded table
SELECT * FROM Table1 AS FirstPass;
// now delete LOCAL records
DELETE FROM Table1
WHERE RecType = `LOCAL';
// show results
SELECT * FROM Table1 AS SecondPass;
// eof |
Figure 15.12. The results of a simple DELETE
statement.
The SQLVB08.SQV script in Listing 15.11 creates a database with one table in it,
populates that table with test data, and then shows the loaded table. Next, a DELETE
statement is executed to remove all records that have a Table1.RecType that
contains LOCAL. When this is done, the results are shown on-screen.
You can create any type of WHERE clause you
need to establish the proper criteria. For example, what if you want to remove all
international (INTL) records where the last payment is after 12/31/95? Edit your copy of SQLVB08.SQV.
Then save and run it to check your results against Figure 15.13. Our version of the
solution appears in Listing 15.12.
Listing
15.12. Using a complex WHERE clause with a DELETE statement.
//
// sqlvb08.sqv - Testing DELETE statements
//
// create a new database
dbMake sqlvb08.mdb;
// create a table to work with
CREATE TABLE Table1
(RecID TEXT(10),
LastName TEXT(30),
FirstName TEXT(30),
RecType TEXT(5),
Amount CURRENCY,
LastPaid DATE
);
// add some records to work with
INSERT INTO Table1 VALUES
(`R01',
`Simmons',
`Chris',
`LOCAL',
`3000',
#12/15/95#
);
INSERT INTO Table1 VALUES
(`R02',
`Walters',
`Curtis',
`INTL',
`5000',
#11/30/95#
);
INSERT INTO Table1 VALUES
(`R03',
`Austin',
`Moro',
`INTL',
`4500',
#01/15/96#
);
// show loaded table
SELECT * FROM Table1 AS FirstPass;
// now delete LOCAL records
DELETE FROM Table1
WHERE RecType = `INTL' AND LastPaid > #12/31/95#;
// show results
SELECT * FROM Table1 AS SecondPass;
// eof |
As you can see from the code in Listing 15.12, you
only need to change the WHERE clause (adding the date criteria) in order to make
the DELETE statement function as planned.
NOTE: You might have noticed that you enclose
date information with the pound symbol (#). This ensures that Microsoft Jet handles the
data as DATE type values. Using the pound symbol works across language settings within the
Windows operating system. This means that if you ship your program to Europe, where many
countries use the date format DD/MM/YY (instead of the U.S. standard MM/DD/YY), Windows
converts the date information to display and compute properly for the regional settings on
the local PC.
Figure 15.13. The results
of the DELETE statement with a complex WHERE clause.
You can also use the DELETE statement to delete records in more than one table at
a time. These multitable deletes can only be performed on tables that have a one-to-one
relationship. The example in Listing 15.13 shows modifications to SQLVB08.SQV to
illustrate the use of the JOIN clauses to create a multitable DELETE
statement. Use SQL-VB5 to edit your copy of SQLVB08.SQV to match the one
in Listing 15.13. Save and execute the script and refer to Figure 15.14 for comparison.
Listing
15.13. Using JOIN to perform a multitable DELETE.
//
// sqlvb08.sqv - Testing DELETE statements
//
// create a new database
dbMake sqlvb08.mdb;
// create a table to work with
CREATE TABLE Table1
(RecID TEXT(10),
LastName TEXT(30),
FirstName TEXT(30),
RecType TEXT(5),
Amount CURRENCY,
LastPaid DATE
);
// add some records to work with
INSERT INTO Table1 VALUES
(`R01',
`Simmons',
`Chris',
`LOCAL',
`3000',
#12/15/95#
);
INSERT INTO Table1 VALUES
(`R02',
`Walters',
`Curtis',
`INTL',
`5000',
#11/30/95#
);
INSERT INTO Table1 VALUES
(`R03',
`Austin',
`Moro',
`INTL',
`4500',
#01/15/96#
);
// create a second table for JOIN purposes
CREATE TABLE Table2
(RecID TEXT(10),
BizPhone TEXT(20),
EMailAddr TEXT(30)
);
// load some data
INSERT INTO Table2 VALUES
(`R01',
`(111)222-3333',
`chris@link.net'
);
INSERT INTO Table2 VALUES
(`R03',
`(777)888-9999',
`moro@band.edu'
);
INSERT INTO Table2 VALUES
(`R04',
`(222)444-6666',
`person@mystery.uk'
);
// show loaded table
SELECT * FROM Table1 AS FirstPass1;
SELECT * FROM Table2 AS FirstPass2;
// now delete records
DELETE Table1.*, Table2.* FROM
Table1 INNER JOIN Table2 ON Table1.RecID = Table2.RecID;
// show results
SELECT * FROM Table1 AS SecondPass1;
SELECT * FROM Table2 AS SecondPass2;
// eof |
Figure 15.14. Results of a multitable DELETE.
The results of this DELETE query might surprise you. Because there is no WHERE
clause in the DELETE statement that could limit the scope of the SQL command, you
might think that the statement deletes all records in both tables. In fact, this statement
only deletes the records that have a matching RecID in both tables. The reason for this is
that you used an INNER JOIN. INNER JOIN clauses operate only on records
that appear in both tables. You now have an excellent way to remove records from multiple
tables with one DELETE statement! It must be pointed out, however, that this
technique only works with tables that have a one-to-one relationship defined. In the case
of one-to-many relationships, only the first occurrence of the match on the many side is
removed.
Here is a puzzle for you. What happens if you only
list Table1 in the first part of that last DELETE statement?
DELETE Table1.* FROM
Table1 INNER JOIN Table2 ON Table1.RecID = Table2.RecID; |
What records (if any) are deleted from Table1? Edit SQLVB08.SQV,
save it, and execute it to find out. Check your results against Figure 15.15.
As you can see from Figure 15.15, a DELETE
query that contains an INNER JOIN only removes records from Table1 that have a
match in Table2. And the records in Table2 are left intact! This is a good example of
using JOIN clauses to limit the scope of a DELETE statement. This
technique is very useful when you want to eliminate duplicates in related or identical
tables. Note also that this INNER JOIN works just fine without the use of defined
constraints or index keys.
Figure 15.15. The results
of a one-sided DELETE using an INNER JOIN.
Summary
You have learned how to add, delete, and edit data
within tables using the DML (Data Manipulation Language) SQL keywords. You've learned
that, by using DML statements, you can quickly create test data for tables and load
default values into startup tables. You also learned that DML statements--such as Append
queries, Make Table queries, and Delete queries--can outperform equivalent Visual Basic
code versions of the same operations.
You learned how to manage data within the tables
using the following DML keywords:
- The INSERT INTO statement can be used to add
new rows to the table using the VALUES clause.
- You can create an Append query by using the INSERT
INTO_FROM syntax to copy data from one table to another. You can also copy data from
one database to another using the IN clause of an INSERT INTO_FROM
statement.
- You can create new tables by copying the structure
and some of the data using the SELECT_INTO statement. This statement can
incorporate WHERE, ORDER BY, GROUP BY, and HAVING
clauses to limit the scope of the data used to populate the new table you create.
- You can use the DELETE FROM clause to remove
one or more records from an existing table. You can even create customized views of the
database using the JOIN clause and remove only records that are the result of a JOIN
statement.
Quiz
- 1. What SQL statement do you use to insert a
single data record into a table? What is the basic form of this statement?
2. What SQL statement do you issue to insert multiple data records into a table?
What is its format?
3. What SQL statement do you use to modify data that is already in a data table?
What is the form of this statement?
4. What SQL statement is used to create new tables that include data from other
tables? What is the format of this statement?
5. What SQL statement do you use to delete one or more records from a data table?
What is the basic format of this statement?
Exercises
- 1. Modify the SQL-VB5 script you
created in Exercise 1 of Day 13 to add the following records.
Data for the CustomerType Table
Customer
Type |
Description |
INDV |
Individual |
BUS |
Business--Non-Corporate |
CORP |
Corporate Entity |
Data for the Customers Table
Field |
Customer
#1 |
Customer
#2 |
Customer #3 |
CustomerID |
SMITHJ |
JONEST |
JACKSONT |
Name |
John Smith |
Jones Taxi |
Thomas Jackson |
CustomerType |
INDV |
BUS |
INDV |
Address |
160 Main Street |
421 Shoe St. |
123 Walnut St. |
City |
Dublin |
Milford |
Oxford |
State |
Ohio |
Rhode Island |
Maine |
Zip |
45621 |
03215 |
05896 |
Phone |
614-555-8975 |
555-555-5555 |
444-444-4444 |
Fax |
614-555-5580 |
555-555-5555 |
444-444-4444 |
- 2. Create a third table that includes data
from the CustomerID, City, and State fields of the Customers table. Call your table
Localities.
3. Write an SQL statement that would delete the SMITHJ record from the Customers
table. What SQL statement would you issue to delete the entire Customers table?
-
|