| SQL Subselect: Soup to Nuts |
|
|
|
| Programming - SQL | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Written by Skip Marchesani | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Tuesday, 06 November 2007 18:00 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Example TablesThe following tables are used in the examples in this article to illustrate how subselect works.
Simple Subselect
The simplest form of subselect can be found in a SELECT statement where a subselect is used to create a selection list for the IN predicate within the WHERE clause.
SELECT nbr, nam, dpt, sal FROM emp
WHERE dpt IN (SELECT dpt FROM dep WHERE dnm LIKE 'S%') ORDER BY nbr This SQL statement retrieves the columns employee number (nbr), employee name (nam), department number (dpt), and salary (sal) FROM the Employee Master table (emp) WHERE the department number (dpt) is IN the list of department numbers (dpt) SELECTed FROM the Department Master table (dep) WHERE the department name (dnm) begins with or is LIKE S. The rows that are retrieved are ORDERed BY employee number (emp).
Subselect TerminologyAt this point and before proceeding further, we need to discuss some subselect terminology. The first SQL statement — in this case, the first SELECT statement — is called the primary or outer SQL statement. In this example, it is called the primary or outer SELECT:
SELECT nbr, nam, sal, dpt, FROM emp
The second SELECT statement is the subselect (also called the inner SELECT):
(SELECT dpt FROM dep WHERE dnm LIKE 'S%')
A maximum of 256 SELECT statements, all referred to as inner selects, can be embedded or nested inside the outer select or outer SQL statement. Please keep in mind that the more subselects you embed together inside an SQL statement, the longer that statement may take to execute. Scalar SubselectA scalar subselect retrieves data from a secondary table based on data in the primary table and can be used anywhere an SQL function or expression is used. Let's modify our simple subselect example to include the department name in the rows returned. To do this, you must add a scalar subselect to the column list of the example immediately after the column named sal, as shown below:
SELECT nbr, nam, dpt, sal,
WHERE dnm LIKE 'S%') This example now contains two subselect statements: The scalar subselect within the column list (SELECT nbr, nam, dpt, sal, (SELECT dnm FROM dep b ...)) and the subselect within the WHERE clause (WHERE dpt IN (SELECT dpt FROM dep ...)) of the outer SELECT statement. Executing this SELECT statement returns the same rows as in the previous example: all the employees who work in a department with a department name that begins with S. However, now the department name is also included.
In this example, what happens if an employee row exists with an invalid department number in it and the scalar subselect cannot find a matching department number in the Department Master table? If this situation occurs, no department number is retrieved and the default value for the column will be used instead. Correlated Naming
In this example, the scalar subselect must use correlated naming (translation: qualified column names) since the emp and dep tables each have a column called dpt and these columns are compared in the WHERE clause (WHERE a.dpt = b.dpt) of the scalar subselect. A qualified column name is required whenever the same column name exists in one or more tables, and a comparison will be made between tables using that column name. Subselect and INSERTSubselect can be used in the INSERT statement to add one or more rows to a table or to initially populate the table with rows. To illustrate this, let's create an Employee Name work table using the CREATE statement and then populate the work table using a simple subselect in the INSERT statement. The CREATE and INSERT statements required to do this are shown below:
CREATE TABLE empname
(number DEC (3,0) NOT NULL WITH DEFAULT, name CHAR (10) NOT NULL WITH DEFAULT, dept DEC (3,0) NOT NULL WITH DEFAULT) INSERT INTO empname SELECT nbr, nam, dpt FROM emp After executing these two SQL statements, the work table contains the following rows:
You should note that the column names in the INTO clause of the INSERT statement must be listed in the same order and must have attributes compatible with the corresponding columns in the CREATE TABLE statement.
CREATE TABLE empname
(number DEC (3,0) NOT NULL WITH DEFAULT, name CHAR (10) NOT NULL WITH DEFAULT, dept DEC (3,0) NOT NULL WITH DEFAULT, dptnam CHAR (10) NOT NULL WITH DEFAULT) INSERT INTO empname SELECT nbr, nam, dpt, (SELECT dnm FROM dep b WHERE a.dpt = b.dpt) AS dptnam FROM emp a
Subselect and CREATE TABLEThis last example can actually be done in one step (instead of two steps) by using a single subselect within the CREATE TABLE statement: the CREATE TABLE followed by the INSERT. To do this, replace the column list in the previous CREATE TABLE statement with subselect from the INSERT statement, as shown below:
CREATE TABLE empname AS
(SELECT nbr, nam, dpt, (SELECT dnm FROM dep b WHERE a.dpt = b.dpt) AS dptnam FROM emp a) WITH DATA
The work table that results from executing this CREATE TABLE is the same as the one that results from executing the INSERT followed by the CREATE TABLE. Subselect and DELETE
You can use subselect in the DELETE statement much the same way you can use it in the INSERT statement.
This table can be referenced in the FROM clause of a subselect within a DELETE statement that will delete those employees that are being transferred, as shown in the following example:
DELETE FROM emp WHERE nbr IN
(SELECT nbr FROM transfer) After the code executes, the three employees will have been deleted from the Employee Master table, and it will contain the following rows:
Subselect and UPDATE
You can use a subselect in an UPDATE statement to update one or more columns in a row from one table based on the value or values retrieved from one or more columns in a row from another table. This is similar to an RPG program that retrieves a column value from a row in a primary table and then chains to a row in a secondary table using that column value as the key. Another, different column value is then retrieved from the row in the secondary table and used to update a corresponding column in the current row of the primary table.
UPDATE emp aa
SET sal = (SELECT nsal FROM newsal bb WHERE aa.nbr = bb.nbr) When using the SQL syntax listed above, each row in the emp table must have a corresponding, matching row in the newsal table, based on employee number (nbr). If you review the rows in the newsal table found in the Example Tables section at the beginning of this article, you will see that this is the case. Therefore, all rows in the emp table are updated and will reflect the new salaries as shown below:
The obvious question is what happens when each row in the emp table does not have a corresponding, matching row in the newsal table. The answer is simple: The update fails with the first row that does not have a match in the newsal table. If you review the rows in the newsal2 table listed in the example tables at the beginning of this article, you will see that employee numbers 40 and 50 do not have corresponding rows in the newsal2 table. If the update of the original emp table is attempted using the newsal2 table, the update fails with the following error message:
UPDATE emp aa
SET sal = (SELECT nsal FROM newsal2 bb WHERE aa.nbr = bb.nbr) Null values not allowed in column or variable SAL.
This UPDATE statement fails at employee number 40 because there is no corresponding employee number 40 row provided in the newsal2 table to update the salary column in the emp table. Therefore, the default update value for the salary column becomes a null, and since the salary column is not null-capable, the UPDATE statement fails at employee number 40. In this situation, the Employee Master table is not journaled and is not using commitment control. Therefore, employee numbers 10, 20, and 30 are successfully updated, but employee number 60 is not.
UPDATE emp aa
SET sal = (SELECT nsal FROM newsal2 bb WHERE aa.nbr = bb.nbr) WHERE aa.nbr IN (SELECT nbr FROM newsal2) The second subselect in the WHERE clause of the UPDATE statement is used to build an IN list based on the employee numbers in the newsal2 table. The result is that only those employee rows in the emp table that have a corresponding matching row in the newsal2 table are updated with a new salary. The result is that employee numbers 10, 20, 30, and 60 are updated with a new salary, but employee numbers 40 and 50 are not updated. The results of the update to the salary column in the emp table are shown below:
Derived Table and Subselect
A derived table is one that does not exist until the SQL statement is executed; it's created dynamically on the fly by the SQL statement execution. A subselect is used in the FROM clause of a SELECT statement to create the derived table as part of the statement execution process.
SELECT * FROM emp
WHERE nbr IN (SELECT number FROM (SELECT dpt, MIN(nbr) AS number FROM emp GROUP BY dpt) AS first_row_table) ORDER BY nbr
This solution employs two subselects, with the innermost subselect using a derived table function. It works as follows: The desired result is to retrieve the first or lowest employee number for each department number in the emp table. To accomplish this, an IN list containing the employee numbers for these rows meeting the above criteria needs to be created within the WHERE clause for the outer SELECT statement.
Take Advantage of Subselect
A subselect allows you to embed up to 256 SELECT statements inside another SELECT, INSERT, UPDATE, DELETE, or CREATE TABLE statement to create very powerful, advanced SQL statements. This provides the capability to reference multiple tables in a SELECT, INSERT, UPDATE, DELETE, or CREATE TABLE statement, without having to do a join of the tables involved. Subselect provides the capability to write a single SQL statement that can perform a complex database task that could require many more lines of code and be significantly more complex if you used a high-level language like RPG, Cobol, C, or Java. The result can be a significant increase in productivity when performing database-related types of tasks. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Last Updated on Friday, 18 April 2008 04:41 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||






[size="1">Code[/size>
[size="1">Code[/size>
[size="1">Code[/size>
[size="1">Code[/size>
[size="1">Code[/size>