Visual C++ 6 Unleashed

Visual C++ 6 Unleashed

By MICKEY WILLIAMS and David Bennett

Data Manipulation Language

In the previous sections, you looked at the parts of SQL used to set up your databases. Now you come to the juicy bits where you actually get your hands on the data and look at the real meat of SQL—Data Manipulation Language (DML). DML consists of the following basic types of statements:

You can probably guess what each of these statements do, but let's look at the specifics of each in the following sections.

SELECT Statements

SELECT is the command that lets you read from your tables. It is one of the most complex SQL commands. Its format is the following:

SELECT  {  DISTINCT  } | select-list  |     *     |
FROM table_list
{ WHERE condition }
{ GROUP BY column_name}
{ HAVING condition }
{ ORDER BY  field_list {DESC }}

The components of the SQL SELECT command are as follows:

Some SQL SELECT examples are shown in Table 19.1.

Table 19.1. SQL SELECT Examples

SQL SELECT Statement Description
SELECT * FROM Employee
ORDER BY Salary, EmpName
This selects all columns and rows from the Employee table. Results are sorted by Salary, and then by employee name.
SELECT EmpName, Salary
FROM Employee
WHERE Salary > 20000
ORDER BY 2
This selects the name and salary for all employees whose salary is greater than $20,000. The results are sorted by Salary (column 2).
SELECT Dept, SUM(salary)
FROM Employee
GROUP BY Dept
HAVING COUNT(*) > 10
This sums the salaries by department for those departments with more than 10 employees.
SELECT Employee.EmpName,
    Department.DeptName
FROM   Employee, Department
WHERE Employee.Salary
     >= 20000
   AND Employee.Dept =
     Department.Dept
This joins the Employee and Department tables by department code (Dept) and then selects the employee name and department name for all employees making a salary of $20,000 or more.

Expressions

In place of individual column names, you can also use numerical expressions involving multiple columns combined with the following arithmetic operators: +, -, /, *. Expressions can be used in the select-list, as in the following example:

SELECT PartNum, PartCost + ExtraCost FROM Parts

The WHERE clause can also include expressions, as in the following example:

SELECT PartNum FROM Parts WHERE (ExtraCost / PartCost) > .25

The LIKE Predicate

In addition to the comparison operators, SQL offers a special comparison operator for character strings. The LIKE predicate allows you to select rows based on a string that matches a certain pattern. In the matching pattern, you can include any normal characters, as well as the special characters % and _. You can attempt to match any string of characters of any length with % or any single character with _. For example, to select any rows that contain Database in the Title field, you can use a query like the following:

SELECT ChapterNum FROM Chapters WHERE Title LIKE '%Database%'

You could also search for titles that have ata starting at the second character position with the following statement:

SELECT ChapterNum FROM Chapters WHERE Title LIKE '_ata%'

The IN Predicate

You can also use the IN predicate to simplify some of your WHERE clauses that are used to select rows with a value that belongs to a certain set of values. For example, look at the following query:

SELECT EmpNum FROM Employee
    WHERE Dept = 'MIS'OR Dept = 'HR'OR Dept = 'Sales'

This could be simplified by using the IN predicate, as in the following query:

SELECT EmpNum FROM Employee WHERE Dept IN ('MIS', 'HR', 'Sales')

You can negate the IN predicate, as in the following example, which selects all employees who aren't in the listed departments:

SELECT EmpNum FROM Employee WHERE Dept IN ('MIS', 'HR', 'Sales')

The BETWEEN Predicate

In many cases, you will need to select rows based on column values that fall into a certain range. For example, you could execute a query like the following:

SELECT EmpNum FROM Employee WHERE Salary > 20000 AND Salary < 30000

This query could be simplified by using the BETWEEN predicate, as in the following ex ample:

SELECT EmpNum FROM Employee WHERE Salary BETWEEN 20000 AND 30000

Like the other comparison operators, you can apply BETWEEN to non-numeric columns, as in the following example:

SELECT EmpNum FROM Employee WHERE Name BETWEEN 'Andersen'AND 'Baker'

You can also negate the BETWEEN predicate by adding the NOT modifier to select rows that don't fall into the given range.

Aggregate Functions

In many cases, you will want to compute values based on all the rows returned in the result set, such as the total for a column in all the returned rows. These sorts of computations can be done with the aggregate functions shown here:

Perhaps the most common use of aggregation is used in retrieving the number of rows returned by a given query, as in the following example, which returns the number of rows in the Employee table:

SELECT COUNT(*) FROM Employee

If you use COUNT(*), all the rows in the query will be counted. However, if you specify a column name, only rows for which the column value is non-null will be counted. For example, if the Dept column was NULL in one or more rows, the following query would return only the number of rows containing a value for Dept:

SELECT COUNT(Dept) FROM Employee

In many cases, you will want to use aggregate functions on certain groups of rows in the result set. This can easily be done by adding a GROUP BY clause, which can specify the column used to group the rows that are included in aggregate computations. The following example will generate a list of department codes, followed by the total of the salaries for each department:

SELECT Dept, SUM(Salary) FROM Employee GROUP BY Dept

Earlier, you saw how the WHERE clause is used to filter the rows that are returned in a query. In a similar fashion, you can restrict the rows returned using aggregation by adding a HAVING clause, as in the following example, which will return only salary totals for departments that have a total salary of less than $200,000:

SELECT Dept, SUM(Salary) FROM Employee
    GROUP BY Dept
    HAVING SUM(Salary) < 200000

In more complicated queries, it can be a bit confusing to see how various WHERE and HAVING clauses work with each other to produce the end result. When working with aggregation, keep in mind that processing is done in the following order:

  1. All rows that meet the WHERE clause are selected.
  2. Aggregate values are computed.
  3. The rows resulting from aggregation are filtered by the HAVING clause.

ODBC SQL Literal Values

In some of the previous examples, you have seen the use of simple literal, or constant, values in the SQL statements. For numeric values, whether integral or floating-point, you need only use the decimal representation. For strings, you simply enclose the string in single quotes. You can also use NULL as a literal when setting a column to a NULL value.

SQL Functions

Databases provide a myriad of functions that allow developers to easily process data. Although each database is different, there are some database functions that seem common to most databases. Table 19.2 defines popular string functions, Table 19.3 defines some popular numeric functions, and Table 19.4 defines some popular date and time functions.

Table 19.2. Popular String SQL Functions

String SQL Function Description
ASCII(string_exp) Returns the ASCII value of the first character in the string.
CHAR(code) Returns the length of the string in characters.
LCASE(string_exp) Returns string_exp converted to all lowercase.
LEFT(string_exp, count) Returns the leftmost count characters of string_exp.
LENGTH(string_exp) Returns the length of string_exp in characters.
LOCATE(string_exp1, string_exp2 [, start]) Returns the starting position of the first occurrence of string_exp1 within string_exp2. Optionally, you can specify a start value to begin searching in string_exp2 at character number start.
LTRIM(string_exp) Returns string_exp with any leading blanks removed.
RIGHT(string_exp, count) Returns the rightmost count characters in string_exp.
RTRIM(string_exp) Returns string_exp with any trailing blanks removed.
SOUNDEX(string_exp) Returns a character string that represents the sound of string_exp.
SUBSTRING(string_exp, start, length) Returns a string made up of length characters taken from string_exp, starting at start.
UCASE(string_exp) Returns string_exp converted to all uppercase.

Table 19.3. Popular Numeric SQL Functions

Numeric SQL Function Description
ABS(numeric_exp) Returns the absolute value of numeric_exp.
ACOS(float_exp) Returns the arccosine of float_exp in radians.
ASIN(float_exp) Returns the arcsine of float_exp in radians.
ATAN(float_exp) Returns the arctangent of float_exp in radians.
CEILING(numeric_exp) Returns the smallest integer greater than or equal to numeric_exp.
COS(float_exp) Returns the cosine of float_exp, where float_exp gives an angle in radians.
COT(float_exp) Returns the cotangent of float_exp, where float_exp gives an angle in radians.
DEGREES(numeric_exp) Returns the angle given in radians in numeric_exp to degrees.
EXP(float_exp) Returns the exponential value of float_exp.
FLOOR(numeric_exp) Returns the largest integer less than or equal to numeric_exp.
LOG(float_exp) Returns the natural logarithm of float_exp.
LOG10(float_exp) Returns the base-10 logarithm of float_exp.
MOD(i1, i2) Returns the modulus (remainder) of i1 divided by i2.
PI() Returns the constant pi (3.14159265…).
POWER(num1, num2) Returns num1 raised to the power of num2.
RADIANS(numeric_exp) Returns the angle given in degrees in numeric_exp to radians.
RAND([seed]) Returns a random, floating-point value. Optionally, you may specify a seed value.
ROUND(num, [decimal]) Returns the value of a rounded numeric expression. You can optionally provide a decimal argument to specify the decimal places to the right of the decimal point. You can provide a negative decimal argument to round to a certain number of decimal places to the left of the decimal point.
SIGN(numeric_exp) Returns -1 if numeric_exp is less than 0, 1 if it is greater than 0, or 0 if numeric_exp is equal to 0.
SQRT(num) Returns the square root of a number.
TAN(float_exp) Returns the tangent of the angle given in radians in float_exp.
TRUNCATE(num, [decimal]) Returns the value of a numeric expression truncated to a given decimal place (default 0). You can provide a negative decimal argument to round to a certain number of decimal places to the left of the decimal point.

Table 19.4. Popular Date and Time SQL Functions

Date/Time SQL Function Description
CURRENT_DATE() Returns the current date.
CURRENT_TIME() Returns the current local time.
CURRENT_TIMESTAMP() Returns the current time and date in a timestamp format. You may specify a precision, in seconds, in timestamp precision.
CURDATE() Returns the current date.
CURTIME() Returns the current time.
DATE(string_exp) Converts a string in 'yyyy-mm-dd'format into a date.
DAYNAME(date_exp) Returns a character string containing the day of the week for date_exp in the data source's local language.
DAYOFMONTH(date_exp) Returns the number of the day of the month for the date in date_exp.
DAYOFWEEK(date_exp) Returns the day of the week as an integer from 1 to 7, with 1 being Sunday.
DAYOFYEAR(date_exp) Returns the day of the year in the range 1–366.
HOUR(time_exp) Returns the hour from time_exp in the range 023.
MINUTE(time_exp) Returns the minute from time_exp in the range 059.
MONTH(time_exp) Returns the month from time_exp in the range 112.
MONTHNAME(date_exp) Returns the name of the month in date_exp.
NOW() Returns a timestamp for the current time and date.
QUARTER(date_exp) Returns the quarter for date_exp, in the range 14. 1 denotes the quarter from January 1 to March 31.
SECOND(time_exp) Returns the second from time_exp in the range 059.
WEEK(date_exp) Returns the week of the year for date_exp in the range 153.
YEAR(date_exp) Returns the year from date_exp.

Joins

One of the more important operations performed with relational databases is the join, which returns rows of data that are gathered from two or more different tables that are joined in the processing of the query. Joins are even more important if you are working with databases that are thoroughly normalized.

To perform a join, select columns from more than one table. For example, assume that you have a Parts table that lists information about parts, including a description, and a separate Prices table that lists pricing information for the parts. The following query would perform a join on these two tables:

SELECT Description, Price FROM Parts, Prices

However, you might be surprised at the results. The preceding example will return the Cartesian product of the two tables, which is a fancy name for all the possible combinations of the rows in the Parts table and the rows in the Prices table. In most cases, this isn't a useful result.

To narrow the set of returned rows to something more useful, you will need to add a WHERE clause. One of the most common cases is when you have a common identifier in both tables. For example, if both the Prices and Parts tables included a PartNum column, you could generate rows that match a part's description to its price with the following query:

SELECT Description, Price FROM Parts, Prices
    WHERE Parts.PartNum = Prices.PartNum

Correlation Names

To help simplify some of your queries, SQL allows you to use table aliases (also known as correlation names), which can reduce the verbosity of your queries and are necessary for some more complicated queries that you will see later. For example, if you had the following query:

SELECT MyFirstTable.Name, MyFirstTable.Num, MySecondTable.Date,
    MySecondTable.Time FROM MyFirstTable, MySecondTable
    WHERE MyFirstTable.Id = MySecondTable.Id

it could be simplified by using the table aliases f, for MyFirstTable, and s, for MySecondTable, as in the following:

SELECT f.Name, f.Num, s.Date, s.Time
    FROM MyFirstTable f, MySecondTable s,
    WHERE f.Id = s.Id

In this case, the use of table aliases doesn't affect the meaning of the query in any way; it merely simplifies the notation. However, in more complicated queries, you might find yourself selecting from the same table more than once, as when using subqueries. In these cases, table aliases are essential for specifying exactly which table you are using.

Outer Joins

The syntax for joins you have seen so far performs an inner join, which might not generate the full Cartesian product of the joined tables. For example, if you created a join with the following query:

SELECT * FROM Employee, Department
    WHERE Employee.DeptNum = Department.DeptNum

the database would process this statement by collecting all the rows present in the Employee table that match those with the rows in the Department table. This result doesn't include results for which no corresponding entry exists in the Employee table. It also won't return any rows for which a matching entry isn't found in the Department table. To create a query that will return rows that don't include a matching row in one of the tables, you will need to use an outer join.

For example, suppose you wanted to select rows for each employee, including those who have not been assigned to a department yet. You can do so by using an outer join like the following:

SELECT * FROM
    Employee LEFT OUTER JOIN Department ON
    Employee.DeptNum = Department.DeptNum

In the preceding example, you used a LEFT OUTER JOIN, which ensures that all rows of the left table (Employee) will be represented in the result set. You could also use a RIGHT OUTER JOIN to ensure that all rows in the right table are represented, or a FULL OUTER JOIN, which ensures that all rows from both tables are represented, whether or not a matching row appears in the other table.

Subqueries

In the WHERE clause examples that you have seen so far, you have done comparisons on literal values or comparing two columns, or Boolean combinations of these. However, it is also possible to retrieve information used in a WHERE clause by executing another query, known as a subquery.

The first case in which a subquery could be used is with an EXISTS (or NOT EXISTS) predicate. Suppose you wanted to select a list of departments that had no employees assigned to them. You could do so with the following query:

SELECT DeptName FROM Department
    WHERE NOT EXISTS (SELECT * FROM Employee)

This will return the name of all departments for which the department number isn't found in any of the records in the Employee table.

You could also select a list of departments that have at least one particularly well-paid employee with a query like the following:

SELECT DeptName FROM Department d
    WHERE EXISTS
        (SELECT * FROM Employee e
        WHERE e.Salary > 100000 AND d.DeptNum = e.DeptNum)

The second case in which subqueries are useful is when using the IN or NOT IN predicates. For example, you could return a list of all the departments that currently have personnel assigned to them by using a query like the following:

SELECT DeptName FROM Department
    WHERE DeptNum IN (SELECT DeptNum FROM Employee)

The third case in which subqueries are often used involve comparisons that use the ANY or ALL keywords. For example, if you kept separate tables for employees and executives, and wanted to select a list of executives who were paid more than all the regular employees (taken individually, not totaled), you could use the following query:

SELECT Ex.Name FROM Executives Ex
    WHERE Ex.Salary > ALL
        (SELECT Emp.Salary FROM Employee Emp)

Similarly, you could use the ANY modifier to select a list of executives for which at least one regular employee was better paid with the following query:

SELECT Ex.Name FROM Executives Ex
    WHERE Ex.Salary < ANY
        (SELECT Emp.Salary FROM Employee Emp)
							

Union Queries

SQL allows you to generate a single result set from two independent queries by combin ing them with the UNION keyword. By default, duplicate rows are removed from the result set, although you can disable this by using UNION ALL instead of UNION. Also, you may choose to sort the end result by specifying an ORDER BY clause, which must come after the last query in the union.

For example, you could generate a list of employees in the MIS and SALES departments with the following query:

SELECT * FROM Employee WHERE Dept = 'MIS'
UNION
SELECT * FROM Employee WHERE Dept = 'SALES'

Of course, there are several other ways that you could more efficiently generate the same results as this query, but this shows a simple example of how UNION works.

INSERT Statements

INSERT puts additional rows into a table. Its format is the following:

INSERT INTO table_name {(column_list)}
| VALUES (values_list)     | SELECT command       |

The parts of the INSERT command are as follows:

Some examples of the INSERT command are shown in Table 19.5.

Table 19.5. SQL INSERT Examples

SQL INSERT Statement Description
INSERT INTO Employee
(EmpName, Salary)
VALUES ('Joe Schmoe',
50000);
This inserts a row into the Employee table containing the name and salary. Any of the variables that aren't listed(such as Dept) are give a NULL value unless a default is specified.
INSERT INTO Employee
VALUES (123, 'Joe Schmoe',
     50000, 'MIS')
If you are adding values for each of the columns, omit the column-list and simply assign values for each of the columns, in the order they appear in the table.
INSERT INTO FormerEmployee
     (EmpId, EmpName, Reason)
  SELECT EmpId, EmpName,
           'Outsourced'
  FROM Employees
  WHERE Dept = 'MIS'
In addition, instead of using the VALUES clause used previously, you could insert rows based on the values returned by a SELECT statement. For example, if your company spun off its MIS department to an outsourcing firm, you could add new records in the FormerEmployee table with a statement like the one in this example.

DELETE Statements

The DELETE command is used to delete existing rows from a table. Its format is as follows:

DELETE FROM table_name
{WHERE search_condition}

The table_name is the name of the table in which you can delete rows. The search_ condition in the WHERE clause is the same as in the SELECT statement.

Some examples of the DELETE statement are shown in Table 19.6.

Table 19.6. SQL DELETE Examples

SQL DELETE Statement Description
DELETE FROM Employee This deletes all rows from the Employee table.
DELETE FROM Employee WHERE EmpId = 456 This deletes all rows from the table whose EmpID is equal to 456.

UPDATE Statements

The UPDATE command is used to update existing rows on a table with new data. Its format is as follows:

UPDATE table_name
SET   column_name1 = expression1,
column_name2 = expression2,...
WHERE condition;

The table_name is the name of the table you want to update. The condition in the WHERE clause is the same as in the SELECT statement. The column_name is a name of a column, and expression is the constant or host variable whose value will be placed inside the column.

Some examples of the UPDATE statement are shown in Table 19.7.

Table 19.7. SQL UPDATE Examples

SQL UPDATE Statement Description
UPDATE Employee
  SET Salary = Salary + 100
This gives every employee a$100 raise.
UPDATE Employee
  SET Salary = Salary + 100,
    dept = NULL
  WHERE dept = 'Payroll'
You can use UPDATE to update more than one column at a time or even set a column to NULL. In this example, you give all employees a $100 raise and take away their department assignment if they are in the payroll department.

Share ThisShare This

Informit Network