Advanced SQL



index
Disabled back button Next Section
printable version

Section 0: Module Objectives or Competencies
Course Objective or Competency Module Objectives or Competency
The student will be able to create database and table structures using the SQL data definition commands. The student will be able to apply the ALTER TABLE command to change a table's structure.
The student will be able to apply advanced SQL statements to make data entries in only part of a row and to delete tables from a database. The student will be able to apply the UPDATE command to make data entries in only part of a row.
The student will be able to apply the DROP TABLE command to delete a table from the database.
The student will be able to sort the results of a SQL SELECT statement, and to generate a listing with duplicates eliminated. The student will be able to apply the ORDER BY clause to order the data sets retrieved from a SQL database.
The student will be able to apply the DISTINCT clause to generate a list of only those values that are different from one another, i.e., with no duplicates.
The student will be able to apply SQL aggregate functions such as counting the number of rows that meet a specified condition, finding the minimum or maximum values for some specified attribute, summing the values in a specified column, or averaging the values in a specified column, as well as knowing how to group rows from a data table when aggregating information, while filtering out rows that do not belong in specified groups. The student will be able to apply the aggregate functions to perform various mathematical summaries, such as counting the number of rows that meet a specified condition, finding the minimum or maximum values for some specified attribute, summing the values in a specified column, or averaging the values in a specified column.
The student will be able to apply the GROUP BY clause to to create frequency distributions by grouping rows from an aggregated data table.
The student will be able to apply the HAVING clause to specify conditions that must be met by the records before they will be listed by the GROUP BY clause, i.e., to specify which grouped records are displayed in a SELECT statement with a GROUP BY clause.
The student will be able to embed a SQL query in another SQL query in order to return data to be used to narrow the scope of the main query. The student will be able to develop nested queries to handle complex queries that depend on the results from another query.
The student will be able to create indexes on database tables in order to speed up data retrieval. The student will be able to apply the CREATE INDEX ON command to create an index on any field that is to be used as a search key, in comparison operations in a conditional expression, or when you want to list rows in a specific order.
The student will be able to apply advanced SQL statements to respond to normalization requirements to change the structure of a database table, to copy selected table columns from a table, and to designate primary and foreign keys. The student will be able to apply the INSERT INTO command to copy selected table columns into a new table if normalization requires that the table be divided into separate table structures.
The student will be able to apply the ALTER TABLE command specify primary and foreign keys for new tables.
The student will be able to apply specialized SQL JOIN operations to combine related rows and non-matching rows from two tables into single virtual tables, as well as to link a table to itself. The student will be able to apply a Left Outer Join using the LEFT JOIN keywords.
The student will be able to apply a Right Outer Join using the RIGHT JOIN keywords.
The student will be able to apply a Full Outer Join using the FULL OUTER JOIN keywords in some RDBMSs.
The student will be able to perform a recursive join to link a table to itself.
The student will be able to write software programs that connect to a database and issue SQL statements to manipulate that database. The student will be able to develop MySQL prepared statements.
Section 1: Changing Table Structure

The ALTER TABLE command can be used to change a table's structure:

ALTER TABLE tableName


ALTER TABLE can be used to change a column's data type.

Example: To change the attribute V_CODE from integer to character:

ALTER TABLE PRODUCT
MODIFY V_CODE VARCHAR(5);

  • Oracle, and some other versions of SQL, will not allow the data type to be changed unless the column is empty.
  • Change the data type of V_CODE in VENDOR as well.

ALTER TABLE can also be used to change attribute characteristics.

Example: To change the width of the PRICE column from eight to nine total digits:

ALTER TABLE PRODUCT
MODIFY P_PRICE DECIMAL(9,2);

  • Changes in a column's characteristics can be made only if those changes do not alter the data type.

ALTER TABLE can be used to add a new column.

Example: To add a column P_SALECODE to the PRODUCT table:

ALTER TABLE PRODUCT
ADD (P_SALECODE CHAR(1));

Note that P_SALECODE will be used in future examples.


ALTER TABLE can also be used to delete a column.

Example: To delete a column V_ORDER from the VENDOR table:

ALTER TABLE VENDOR
DROP COLUMN V_ORDER;

Multiple columns can be dropped byt listing them individuall, such as

ALTER TABLE T1
DROP COLUMN C2,
DROP COLUMN C3;

Section 2: Updates

The UPDATE command can be used to make data entries in only part of a row.

Recall that the INSERT command can only be used to enter a full row of data.


To enter the P_SALECODE value '2' in the fourth row:

UPDATE PRODUCT
SET P_SALECODE = '2'
WHERE P_CODE = '1546-QQ2';

SELECT P_CODE, P_DESCRIPT, P_INDATE, P_PRICE, P_SALECODE
FROM PRODUCT
WHERE P_CODE = '1546-QQ2';

Results of update.


To enter the P_SALECODE value '1' in specific rows:

UPDATE PRODUCT
SET P_SALECODE = '1'
WHERE P_CODE IN ('2232/QWE', '2232/QTY');

SELECT P_CODE, P_DESCRIPT, P_INDATE, P_PRICE, P_SALECODE
FROM PRODUCT
WHERE P_CODE IN ('2232/QWE', '2232/QTY');

Result of second update.


To assign a sales code based on the P_INDATE:

UPDATE PRODUCT
SET P_SALECODE = '2'
WHERE P_INDATE < '2009-12-25';

UPDATE PRODUCT
SET P_SALECODE = '1'
WHERE P_INDATE >= '2010-01-16' AND P_INDATE <= '2010-02-10';

SELECT P_CODE, P_DESCRIPT, P_INDATE, P_PRICE, P_SALECODE
FROM PRODUCT;

Results of update 3.



Here is a script for table creation: link. The P_SALECODE field has already been added and populated.




Calculations

Calculations can easily be embedded in UPDATE queries.

After restocking, to add 20 units of product 2232/QWE:

UPDATE PRODUCT
SET P_QOH = P_QOH + 20
WHERE P_CODE = '2232/QWE';

To add 10 percent to the price for all products that have current prices below $50:

UPDATE PRODUCT
SET P_PRICE = P_PRICE * 1.10
WHERE P_PRICE < 50.00;

The following query calculates the value of the complete inventory of rat-tail files (assuming P_PRICE is purchase price):

SELECT P_CODE, P_DESCRIPT, (P_QOH * P_PRICE) AS `INVENTORY VALUE`
FROM PRODUCT
WHERE P_CODE = '54778-2T';

Result of calculations.

Notice the use of AS to give the results a meaningful name. This is referred to as a "column alias".

Section 3: Deleting a Table from the Database

A table can be deleted from the database using the DROP TABLE command.

DROP TABLE table_name;

For example, to delete the PART table:

DROP TABLE PART;

A table can be dropped only if it is not the "one" side of a relationship.

If you want to remove table in a different database, you need to use the following syntax:

DROP TABLE database_name.table_name;

You should be very careful while using this command because once a table is deleted then all the information available in that table will also be lost forever.

Section 4: Ordering a Listing

The ORDER BY clause is used to order the data sets retrieved from a SQL database.

The ORDER BY clause must always be listed last in the command sequence.

To produce a list in ascending order, use the clause:

ORDER BY columnList

To produce a list in descending order, use the clause:

ORDER BY columnList DESC

For example, to list PRODUCT by P_PRICE in ascending order:

SELECT P_CODE, P_DESCRIPT, P_INDATE, P_PRICE
FROM PRODUCT
ORDER BY P_PRICE;

Result of ORDER BY.

To list PRODUCT by P_PRICE in descending order:

SELECT P_CODE, P_DESCRIPT, P_INDATE, P_PRICE
FROM PRODUCT
ORDER BY P_PRICE DESC;

You can use the ORDER BY clause in conjunction with other SQL commands:

SELECT P_DESCRIPT, V_CODE, P_INDATE, P_PRICE
FROM PRODUCT
WHERE P_INDATE < '2010-01-21' AND P_PRICE <= 50.00
ORDER BY V_CODE, P_PRICE DESC;

Result of another ORDER BY.

Here is a slightly altered example, but with V_CODE in descending order as well:

SELECT P_DESCRIPT, V_CODE, P_INDATE, P_PRICE
FROM PRODUCT
WHERE P_INDATE < '2010-01-21' AND P_PRICE <= 50.00
ORDER BY V_CODE DESC, P_PRICE DESC;

Result of another ORDER BY.
Section 5: Eliminating Duplicates

The DISTINCT clause will yield a list of only those values that are different from one another, i.e., duplicates are eliminated.

For example, to create a list of vendor codes from the PRODUCT table with no duplication:

SELECT DISTINCT V_CODE
FROM PRODUCT;

Result of DISTINCT clause.

To get a sorted list of vendor codes from the PRODUCT table with no duplication, you must use the ORDER BY clause:

SELECT DISTINCT V_CODE
FROM PRODUCT
ORDER BY V_CODE;

Result of DISTINCT and ORDER BY clauses.
Section 6: Aggregate Functions

SQL can perform various mathematical summaries for you, such as counting the number of rows that meet a specified condition, finding the minimum or maximum values for some specified attribute, summing the values in a specified column, or averaging the values in a specified column.

Aggregate functions perform a variety of actions such as counting all the rows in a table, averaging a column's data, and summing numeric data.

Function Output
COUNT The number of rows containing non-NULL values.
MIN The minimum attribute value encountered in a given column.
MAX The maximum attribute value encountered in a given column.
SUM The sum of all values for a given column.
AVG The arithmetic mean (average) for a specified column.

Notes:

Use aggregate functions as expressions only in the following situations:

In other words,


COUNT: counts the number of specific values of an attribute.

To count the number of vendors in the PRODUCT table:

SELECT COUNT( DISTINCT V_CODE )
FROM PRODUCT;

Example of COUNT.

Recall that aggregate functions can be used with or without a WHERE clause specifying conditions.

To find the number of vendors referenced in the PRODUCT table who have supplied products with prices that are less than, or equal to, $10.00:

SELECT COUNT( DISTINCT V_CODE )
FROM PRODUCT
WHERE P_PRICE <= 10.00;

Example of COUNT.

SELECT COUNT(*) will return the number of total rows returned by the query, including the rows that contain NULLs.

SELECT COUNT( * )
FROM PRODUCT
WHERE P_PRICE <= 10.00;


MAX: finds the highest (maximum) value for a given attribute.

To find the highest P_PRICE in the PRODUCT table:

SELECT MAX( P_PRICE )
FROM PRODUCT;

Results of MAX.

It was pointed out earlier that aggregate functions cannot be used in a WHERE clause. Hence, the following query is invalid:

SELECT P_CODE, P_DESCRIPT, P_PRICE
FROM PRODUCT
WHERE P_PRICE = MAX( P_PRICE );

We'll see how to find the product that has the highest price in the next section.


MIN: finds the lowest (minimum) value for a given attribute.

To find the product with the oldest date:

SELECT MIN( P_INDATE )
FROM PRODUCT;

Results of MIN.

To find the product that has the lowest inventory value:

SELECT *
FROM PRODUCT
WHERE P_QOH*P_PRICE = (SELECT MIN(P_QOH*P_PRICE) FROM PRODUCT);

Results of aggregate function with expression.

SUM: computes the total for any specified attribute.

To find the total value of all items carried in inventory:

SELECT SUM ( P_QOH * P_PRICE ) AS `TOTAL VALUE`
FROM PRODUCT;

Again, notice the use of AS to give the results an alias, and note the back quotes that are required in MySQL.


AVG: determines the average value of a specific attribute.

To determine the average P_PRICE value:

SELECT AVG ( P_PRICE )
FROM PRODUCT;

Results of AVG.
Section 7: Grouping Data

The GROUP BY clause specifies how to group rows from a data table when aggregating information, while the HAVING clause filters out rows that do not belong in specified groups.

The GROUP BY clause can be used to create frequency distributions.

Aggregate functions are normally used in conjunction with a GROUP BY clause.

The GROUP BY clause enables you to use aggregate functions to answer more complex managerial questions such as

The syntax is:

SELECT columnList
FROM tableList
[WHERE conditionList ]
[GROUP BY columnList ]
[HAVING conditionList ]
[ORDER BY columnList [ASC | DESC] ];

MySQL evaluates the GROUP BY clause after the FROM and WHERE clauses and before the HAVING, SELECT, DISTINCT, ORDER BY and LIMIT clauses:

Group By precedence

Examples

To find the minimum price for each sale code:

SELECT P_SALECODE, MIN( P_PRICE )
FROM PRODUCT
GROUP BY P_SALECODE;

Results of GROUP BY.

To find the average price within each sales code:

SELECT P_SALECODE, AVG( P_PRICE )
FROM PRODUCT
GROUP BY P_SALECODE;

Results of GROUP BY.

If you dislike those extraneous digits to the right of the decimal, ROUND:

SELECT P_SALECODE, ROUND( AVG( P_PRICE ), 2)
FROM PRODUCT
GROUP BY P_SALECODE;

Results of GROUP BY.

This example lists the number of products by vendor along with the average price:

SELECT V_CODE, P_DESCRIPT, COUNT(DISTINCT(P_CODE)), AVG(P_PRICE)
FROM PRODUCT
GROUP BY V_CODE;

Note that in previous versions of MySQL, GROUP BY could be used to provide sorting as well. If a query specified GROUP BY, the result was sorted as if ORDER BY was present in the query. Newer versions will no longer support either implicit or explicit sorting for GROUP BY (link).


HAVING Clause

The HAVING clause is used to specify conditions that must be met by the records before they will be listed by the GROUP BY clause, i.e., it specifies which grouped records are displayed in a SELECT statement with a GROUP BY clause.

Example:

SELECT P_DESCRIPT, SUM(P_QOH)
FROM PRODUCT
GROUP BY P_DESCRIPT
HAVING SUM( P_QOH ) > 100;

Results of HAVING.

This example lists the number of products by vendor along with the average price, but includes only the rows with an average price below 10.00:

SELECT V_CODE, COUNT(DISTINCT(P_CODE)), AVG(P_PRICE)
FROM PRODUCT
GROUP BY V_CODE
HAVING AVG(P_PRICE) < 10;

Results of HAVING.

The following Learn Basic SQL Commands video discusses SELECT, FROM, WHERE, GROUP BY, HAVING, and ORDER BY.


Additional Resources

Section 8: Nested Queries

We learned how to find the highest price in the PRODCUT table, but it is considerably more difficult to find the product associated with the highest price.

Nested queries, or subqueries or inner queries, are a tool for performing operations in multiple steps.

To find the product that has the highest price:

SELECT P_CODE, P_DESCRIPT, P_PRICE
FROM PRODUCT
WHERE P_PRICE = (SELECT MAX( P_PRICE ) FROM PRODUCT);

Results of MAX.

A nested query (or subquery) is composed of two parts:

To list in descending order all products whose price exceeds the average price:

SELECT P_CODE, P_DESCRIPT, P_INDATE, P_QOH, P_MIN, P_PRICE, P_DISCOUNT, V_CODE, P_SALECODE
FROM PRODUCT
WHERE P_PRICE > ( SELECT AVG( P_PRICE ) FROM PRODUCT )
ORDER BY P_PRICE DESC;

Results of nested query.

Intermediate Query Approach

Alternate approach – intermediate queries instead of nested queries:

CREATE TABLE Q1a_results
SELECT AVG( P_PRICE ) AS AvgPrice
FROM PRODUCT;

SELECT P_CODE, P_DESCRIPT, P_INDATE, P_QOH, P_MIN, P_PRICE, P_DISCOUNT, V_CODE, P_SALECODE
FROM PRODUCT, Q1a_results
WHERE P_PRICE > Q1a_results.AvgPrice
ORDER BY P_PRICE DESC;

Section 9: Indexes

Indexes are special lookup tables that the database search engine can use to speed up data retrieval by improving the efficiency of searches.

While the DBMS automatically creates a unique index when you designate a primary key, you sometimes need additional indexes.

Indexes are special lookup tables that the database search engine can use to speed up data retrieval.

SQL indexes can be created on the basis of any selected attribute.

CREATE [UNIQUE] INDEX indexName
ON tableName (column1 [, column2])

For example, to create an index named P_INDATEX based on the attribute P_INDATE of PRODUCT:

CREATE INDEX P_INDATEX ON
PRODUCT(P_INDATE);

A common practice is to create an index on any field that is used as a search key, in comparison operations in a conditional expression, or when you want to list rows in a specific order.

By default, all indexes produce results that are listed in ascending order, but you can alter that:

CREATE INDEX PROD_PRICEX
ON PRODUCT(P_PRICE DESC);

To delete an index, use DROP INDEX:

DROP INDEX PROD_PRICEX;


Although indexes are intended to enhance a database's performance, there are times when they should be avoided.

The following guidelines indicate when the use of an index should be reconsidered.


For more on indexes:

Section 10: Copying Parts of Tables

If normalization requires that a table be divided into separate table structures, SQL allows selected table columns to be copied.

INSERT INTO target_tableName [(target_columnlist)]
SELECT source_columnlist
FROM source_tablename;

To copy selected table columns from a table, first create a new table structure to receive the data.

CREATE TABLE PART (
PART_CODE VARCHAR(10) NOT NULL UNIQUE,
PART_DESCRIPT VARCHAR(35),
PART_PRICE DECIMAL(8,2),
V_CODE VARCHAR(5),
PRIMARY KEY (PART_CODE));

INSERT INTO PART (PART_CODE, PART_DESCRIPT, PART_PRICE, V_CODE)
SELECT P_CODE, P_DESCRIPT, P_PRICE, V_CODE FROM PRODUCT;

SELECT * FROM PART;

Results of Create Table.


SQL provides another way to rapidly create a new table based on selected columns and rows of an existing table, but the syntax varies from one RDBMS to another.

Here is the syntax in MySQL:

CREATE TABLE PART2
SELECT P_CODE AS PART_CODE, P_DESCRIPT AS PART_DESCRIPT,
P_PRICE AS PART_PRICE, V_CODE
FROM PRODUCT;

When you create a new table based on another table (using the CREATE TABLE ... SELECT approach), the new table does not include the integrity rules from the original table.

SQL Server and Access use the SELECT INTO command to accomplish a similar task.

Section 11: Primary and Foreign Key Designation

Primary and foreign keys can be specified for new tables.

Recall that when you create a new table based on another table (using the CREATE TABLE ... SELECT approach), the new table does not include a primary key.

To define a primary key for the new PART2 table, use the following:

ALTER TABLE PART2
ADD PRIMARY KEY (PART_CODE);


Other scenarios could leave a table without entity and referential integrity:

To designate the PART table's foreign key:

ALTER TABLE PART2
ADD CONSTRAINT V_CODE
FOREIGN KEY (V_CODE) REFERENCES VENDOR (V_CODE);

You can incorporate both changes at once:

ALTER TABLE PART2
ADD PRIMARY KEY (PART_CODE)
ADD CONSTRAINT V_CODE
FOREIGN KEY (V_CODE) REFERENCES VENDOR (V_CODE);

Section 12: Outer Join (Left and Right)

The image below again shows the results of inner joining the PRODUCT and VENDOR tables.

Results of JOIN.

Difference

Though both inner and outer joins include rows from both tables when the match condition is successful, they differ in how they handle a false match condition.

Inner joins do not include non-matching rows; whereas, outer joins do include them.


Hence, to include the missing rows in the result, an Outer Join is required.

There are two types of outer join: left and right.

The Left Outer Join returns not only the rows matching the join condition (that is, rows with matching values in the common column) but also the rows in the left-side table with unmatched values in the right-side table.

The Left Outer Join returns all records from the left table, and the matched records from the right table.

Example: To see all VENDOR rows and all matching PRODUCT rows (i.e., reveal all the vendors who supply no products) a left outer join can be used:

SELECT P_CODE, VENDOR.V_CODE, V_NAME
FROM VENDOR LEFT JOIN PRODUCT
ON VENDOR.V_CODE = PRODUCT.V_CODE;

Result of left join.

The Right Outer Join returns not only the rows matching the join condition (that is, rows with matching values in the common column) but also the rows in the right side table with unmatched values in the left side table.

The Right Outer Join returns all records from the right table, and the matched records from the left table.

Example: To see all PRODUCT rows with all matching VENDOR rows (i.e., all the products that currently have no vendor to supply them) a Right Outer Join can be used:

SELECT P_CODE, VENDOR.V_CODE, V_NAME
FROM VENDOR RIGHT JOIN PRODUCT
ON VENDOR.V_CODE = PRODUCT.V_CODE;

Result of right join.

There is also a Full Outer Join that uses the keywords FULL OUTER JOIN to return all records when there is a match in either left or right table, but not directly in MySQL.

Section 14: Top Clause

The Top clause tells the query engine to return the specified number of records.

Top is not ANSI/ISO compliant.

This example returns the top 3 records based on P_PRICE:

SELECT P_DESCRIPT, P_PRICE
FROM PRODUCT
ORDER BY P_PRICE
LIMIT 0,3;

Results of LIMIT.

To get the top three prices (highest):

SELECT P_DESCRIPT, P_PRICE
FROM PRODUCT
ORDER BY P_PRICE DESC
LIMIT 0,3;

Results of LIMIT.

The TOP clause is only supported by the SQL Server and MS Access database systems.

Section 15: MySQL Prepared Statements (Parameterized Queries)

A parameterized query (referred to as a prepared statement in MySQL) is a query in which placeholders are used for parameters and the parameter values are supplied at execution time, typically by prompting the user to enter a parameter value.


Developing a Prepared Statement

While MySQL prepared statements are not exactly the same as parameterized queries, they are the closest alternative.

In order to use MySQL prepared statements, you use the three following statements:

Here is an example:

PREPARE listModels FROM
"SELECT modelNum, modelDescription, modelManufacturer, modelInventoryCount
FROM productcategory
WHERE modelDescription LIKE ?";

SET @modelDesc = 'Kiteboard%';

EXECUTE listModels USING @modelDesc;
DEALLOCATE PREPARE listModels;

The query can be enclosed in single or double quotes, but if you use a single quote as part of the query, e.g., as part of a CONCAT operation, then you need to use double quotes around the query.



Saving a Prepared Statement as a Stored Procedure

In phpMyAdmin, you can create the prepared statement as a stored procedure that includes a parameter to which the placeholder can be compared.

  • When the stored procedure that contains the prepared statement is executed, phpMyAdmin will open a dialog box that allows the user to provide the value to which the placeholder will be compared.

Here is an example:

DELIMITER $$
CREATE PROCEDURE `modelListPreparedStatement` (IN `modelDesc` varchar(45))
BEGIN
PREPARE listModels FROM
"SELECT modelNum, modelDescription, modelManufacturer, modelInventoryCount
FROM productcategory
WHERE modelDescription LIKE ?";
EXECUTE listModels USING modelDesc;
DEALLOCATE PREPARE listModels;
END$$
DELIMITER ;

The dialog box for this example is shown below. The user enters the comparison value in the Value input field.

Prepared Statement Dialog Box.jpg



Using prepared statements with placeholders for parameter values has the following benefits:

To learn more about Prepared Statements, visit these links: