Professional Documents
Culture Documents
SQL by Example - Learn How To CR - Charlotte McGary PDF
SQL by Example - Learn How To CR - Charlotte McGary PDF
Charlotte McGary
Copyright © 2014 Charlotte McGary. All Rights Reserved.
Prerequisites
The examples in this book access Microsoft SQL Server 2008 R2
SP2 Express Edition and the pubs database using Microsoft SQL
Server Management Studio. If you do not have access to a SQL
Server, you will need to download and install both the free Express
Edition and the pubs database on your computer. For download and
installation instructions, see Appendix A: Installing SQL Server.
LESSON 1
In this lesson you will learn about:
Tables
If you’ve ever seen an Excel spreadsheet, then a typical database
structure will look familiar. A database is usually divided into
separate tables with a grid structure, each table containing related
data (like a file in a file cabinet). For example, a car dealership would
have one table for customers and a separate one for inventory. The
customer table can contain only customer information, and the
inventory table can contain only information about cars in the
dealer’s inventory.
Columns
A column is one field in a table. Many examples in this book use a
publisher’s database named pub that contains an authors table with
the following columns (fields):
NOTE:
Column names cannot have any embedded spaces. Putting spaces
in names can cause all sorts of difficulties. Therefore, to separate
words in table and field names, use an underscore ( _ ) instead of a
space.
Rows
A row is one record of data, similar to a row of data in Microsoft
Excel. Using our authors table from the previous example, the
following two records show five of the eight columns of data related
to authors Abraham Bennet and Marjorie Green.
Data types
Each field has a specific data type associated with it. The data type
determines what type of data is allowed in that column. In the above
example, state column allows only character values. A list of
commonly used data types follows:
NOTE:
CHAR vs. VARCHAR
Unless you have a fixed-length data type such as a zip code, state
abbreviation, or a phone number, it is more efficient to use the
VARCHAR data type for strings. The CHAR data type will reserve
storage space for the maximum number of declared characters,
whether or not they are all used (fills unused area with trailing
spaces). The VARCHAR data type only store the characters actually
used, saving memory and disk storage.
You can see the data type of each column in our authors table by
clicking on the plus (+) symbol to the left of each of the following in
the SQL Server Management Studio Object Explorer pane:
+Databases
+pubs
+Tables
+dbo.authors
+Columns
NULL Values
The term NULL value means no data has been entered. This is not
the same as a space character or a zero, as both “ ” and “0”
represent actual values. If you create a local database, it is tied to you
(the owner) and will not be accessible to others at a global level.
These tables are usually prefaced with “dbo.” (data base owner), the
default database user.
Comments
It is often helpful to add comments to your saved queries, especially
when you have a long series of SQL statements. Comments are
used for various purposes: identifying the author of the query,
explaining the purpose of different sequences of code, and so on.
Comments do not appear in query results. The syntax for comments
is as follows:
-- Single line comment or /* Single line comment */
/* Multiple line
comment */
Asking simple questions with
SQL
Short for Structured Query Language, SQL (pronounced sequel) is a
language used for communicating with databases. It’s a powerful yet
straight-forward and easy-to-learn language that can be used with
almost any DBMS. All the example queries used in this document
were executed using SQL Server Management Studio. See
Appendix A: Installing SQL Server for instructions on using this
DBMS.
Just as any language must follow a set of rules called grammar, SQL
also has a set of rules it must follow. The English language has
verbs, nouns, adjectives, and adverbs. SQL has some similar
constructs. For example, suppose you’re an assistant to a publisher,
and he keeps all his records in a filing cabinet. He has a folder in that
cabinet labeled “Authors”, with the information related to each author
printed on a separate piece of paper within that folder. Now if the
publisher wants you to retrieve that information, he might say “Get
me a list of all the authors we’ve published.” This lesson will show
you how to translate that request into SQL.
In the examples in this book, our digital filing cabinet is a database
named pubs, which contains our digital folders (tables named
authors, publishers, titles, and so on).
Selecting data
In order to retrieve one or more records, you must tell SQL what
information you want and where that information resides. For the
most simple queries, this can be accomplished using the keywords
USE, SELECT, and FROM.
USE database_name
To retrieve data from all columns in a record, simply type the word
SELECT followed by an asterisk (*). An asterisk is a wildcard, which
represents all data. For more information, see Wildcards.
SELECT *
FROM table_name
Running your first query
The first query you’re going to run retrieves data from the table
dbo.authors. Click New Query on the Standard Toolbar.
In the query pane to the right of the Object Explorer, enter the following
text (as you type, keywords automatically appear as blue text):
USE pubs
SELECT * FROM dbo.authors;
The semicolon (;) at the end indicates the query is complete (similar
to a period at the end of a sentence).
SELECT *
FROM dbo.authors
ORDER BY au_lname;
The first five results are displayed below:
You can also select specific columns. For example, to list only the
author’s last names, you can select just the au_lname column. This
is a matter of simply replacing the asterisk “*” in the previous
example with the column name as follows:
SELECT au_lname
FROM dbo.authors;
NOTE:
The column named “state” is rendered in blue text because it is also
a reserved word. In this case, SQL is smart enough to know you’re
referring to your column name, but still lets you know it’s a reserved
word. If you don’t want it to appear in blue text, just enclose the
column name in square brackets like this: [state].
Examples
Find all titles with a price less than $19.99 and sort in ascending
order by price:
Find all titles whose price is between $10 and $25 and sort in
ascending order by price:
Find all titles whose price is NOT between $10 and $25 and sort in
ascending order by price:
or
Find all publishers where the value in the state column is not NULL.
Wildcards
Wildcards allow you more flexibility in your queries, as they don’t
require an exact match.
To further filter the results so that records are displayed only authors
with a last name beginning with “G” who also live in CA, modify your
query as follows:
You will find the operators AND, OR, and NOT quite useful for this
type of situation.
List all cities whose name is two or more words and sort in
ascending order:
SELECT city
FROM dbo.authors
WHERE city LIKE '% %'
ORDER BY city;
To only list cities with three or more words in the name, modify the
string associated with the LIKE operator by adding a second space
and a third % as follows:
SELECT city
FROM dbo.authors
WHERE city LIKE '% % %'
ORDER BY city;
List all authors who have a two-word last name that includes a
space:
SELECT *
FROM dbo.authors
WHERE au_lname LIKE '_ _ _ %';
The above query uses 3 successive ( _ ) wildcard characters (no
spaces between the underscores) followed by a space character and
any number of characters. Each underscore represents a single
character, while the % symbol represents any number of characters.
The IN operator
In the first section of this document, you learned how to use the
WHERE clause with the AND and OR operators to specify more than
one condition. If you have more than two conditions, however, the IN
operator makes your query less cumbersome to write.
For example, suppose you want to display the author’s last name,
first name, city and state if the author lives in CA, OR, or UT. You
could write the following query using the OR operator:
SELECT au_lname, au_fname, city, [state]
FROM dbo.authors
WHERE [state] = 'MD' OR [state] = 'KS' OR [state] = 'OR';
Or, you could get the same results with less typing with the IN
operator as follows:
SELECT au_lname, au_fname, city, state
FROM dbo.authors
WHERE state IN ('MD', 'KS', 'OR');
Aliases
Calculated columns
Aggregate functions
Converting data types
Grouping data
Using Aliases
An alias is just what the name implies: an alternate name for either a
column or a table name. They can significantly reduce the amount
text you have to type and make your queries easier for you to read.
They are especially useful when creating a column from a calculation
and when querying multiple tables. An alias does not change the
name of the column; it’s just a temporary name used for display
output.
To create an alias, simply type the column name followed by the text
“AS” and the name you want to use as an alias for your column or
table. (Table aliases will be discussed in Lesson 3.)
The following query will replace the column name “pub_name” with
the text “Publisher’s Name” in the resulting display.
USE pubs
SELECT pub_name AS "Publisher's Name"
FROM dbo.publishers;
Query #1:
SELECT 2 + 4 * 3; Result is 14.
Query #2:
SELECT (2 + 4) * 3; Result is 18.
In the following query, “price” is the data type MONEY and 0.095 is
FLOAT. The resulting data type of both calculated columns is FLOAT
because that data type has a higher precedence than MONEY.
USE pubs
SELECT title, price,
price * 0.095 AS "9.5% Tax",
price + price * 0.095 AS "Total"
FROM dbo.titles;
The first 5 results are displayed below:
SELECT COUNT(*)
FROM dbo.titles;
The above query counts the total number of records whether or not a
record has a column containing a NULL value. To find, for example,
the number of records with a non-null price, execute the following
query:
SELECT COUNT(price)
AS "Records with non-null prices"
FROM dbo.titles;
Since there are two records containing a NULL value in the price
column, the COUNT function displays 16 instead of 18 as the
number of records found.
The following query lists all records containing an author ID. If you
execute the query, you will get 25 records. Some of the IDs are
repeated because those authors have written more than one book.
SELECT au_id
FROM dbo.titleauthor
ORDER BY au_id;
To find out exactly how many unique authors there are in the table,
execute the following query:
The results will correctly show that 19 authors wrote the 25 books in
the database.
If you just want to list the title_id, price, ytd_sales, and your
calculated column, you could alter the query as follows:
You could have run this as two separate queries, one for MIN and
one for MAX, but it makes more sense to see both results side-by-
side.
To display the minimum price, the maximum price, and the difference
between them, execute the following query:
SELECT MIN(price) AS "Min Price",
MAX(price) AS "Max Price",
MAX(price) - MIN(price) AS "Difference"
FROM dbo.titles;
Converting Data Types
CAST( ) and CONVERT( )
There may be times when values you retrieve are not the correct
data type you need for calculations. There are two functions which
can convert data from one data type to another: CAST() and
CONVERT(). CAST is the ANSI standard. CONVERT is specific to
Microsoft SQL Server. CONVERT allows more flexibility than CAST
through the use of a third argument (style).
The data type you’re converting from must be compatible with the
data type you’re converting to. For example, you can convert a
numeric value into a character value, but attempting to convert a
character value to a numeric value, you will get a conversion error
(unless you’re converting a character value like a zip code which has
only the characters 0-9).
Why convert, you ask? Good question. See if you can deduce the
answer from the following example, where x = 2 and y = 3 and both x
and y are the integer data type.
Equation: x/y
If x and y are data type FLOAT, where x = 2 and y = 3, the result will
be 0.666666666666667.
If you divide one INT data type by another INT data type, the result
may surprise you, as in the following example:
or
USE pubs
SELECT title, price,
price * 0.095 AS "9.5% Tax",
price + (price * 0.095) AS "Total"
FROM dbo.titles;
Conversion Tips
Always remember to convert integers to decimal or floating point
values when the result of an integer division is used as the value in a
denominator, (e.g. 10 / (2/3)). For example, you know that when you
divide 2 by 3, you get 0.67. But that is not how SQL sees the result.
Integer results are truncated, not rounded up or down, so anything
after the decimal point is simply thrown away. Therefore, according
to SQL, the result of the integer division 2/3 is 0, which results in a
“divide by zero error” (see the example below).
SELECT 2 / (1/3 )
SELECT CONVERT(DECIMAL(6,2),
CONVERT(DECIMAL(6,2),2) / CONVERT(DECIMAL(6,2),3))
AS "Result 4";
The GROUP BY clause
As you learned in the previous lesson, ORDER BY is used to sort
data in ascending or descending order. GROUP BY, on the other
hand, is typically used with aggregate functions (such as COUNT,
AVG, MIN, MAX) to group identical data. This is best explained by
comparing the following two examples.
To find the number of titles for each publisher, you’d have to run the
following query once for each publisher:
The GROUP BY clause allows you to retrieve the number of titles for
each publisher in one query:
NOTE:
Unlike the ORDER BY clause, a column name specified in the
SELECT statement that’s not part of an aggregate function must
appear in a GROUP BY clause.
SELECT title_id,
CAST(
(AVG(hirange)-AVG(lorange)) * AVG(royalty*.01)
AS MONEY) AS "Avg. paid in royalties"
FROM dbo.roysched
GROUP BY title_id;
SELECT price,
COUNT(price) AS "#@ at this price"
FROM dbo.titles
GROUP BY price
HAVING price IS NOT NULL;
The following query displays all prices that have more than one title
sold at that price:
SELECT pub_id,
COUNT(pub_id) AS Title_count
FROM dbo.titles
GROUP BY pub_id
HAVING COUNT(pub_id) > 5
ORDER BY COUNT(pub_id);
Notice that there are no quotes around the column alias Title_count.
That is because you only need to include the quotes when you
embed spaces in the name (i.e. “Title count”).
To find the number of authors living in zip codes beginning with “94”,
execute the following query:
SELECT zip,
COUNT(au_id) AS Au_count_by_zip
FROM dbo.authors
GROUP BY zip
HAVING zip LIKE '94%'
To find the number of titles and the sum of the year-to-date sales for
each type of book, ignoring books where the type category hasn’t yet
been decided, execute the following query:
Notice that one title “Sushi, Anyone?” is listed twice. That is because
it has three authors: au_ord valuels of 1, 2, and 3.
To find the total number of authors for titles having more than one
author, change the previous query to find the highest au_ord value
and group by title:
SELECT
a_column_name, aggregate_function_name (a_column_name)
OVER (PARTITION BY a_column_name) AS alias
USE pubs
SELECT title_id,
SUM(qty) AS "Qty/title all stores"
FROM dbo.sales
GROUP BY title_id;
Now look at the following query that produces the same results using
an OVER (PARTITION BY) clause (the text is case-insensitive):
However, if you were to try to add the title to the SELECT statement
in the GROUP BY query, you would receive an error:
The OVER (PARTITION BY) clause allows you to add the title
without an error:
3. Using the pubs database, query the dbo.titles table to list the
book type and the number of publishers that carry each type
of book, ignoring any title with the type UNDECIDED. Use the
column alias “Num. pubs publishing this type” for your
calculated value.
Suppose you want to display every title and its publisher. The
dbo.publishers table contains both the publisher’s ID and name, but
no title information. The dbo.titles table contains the book titles and
the publisher’s ID, but not the name of the publisher. Therefore,
you’ll need to query both tables to get all the information you need.
The WHERE clause specifies which column we’re using to join the
tables (see also Inner Joins). In this example we’re matching the
pub_id in both tables, so only titles in the dbo.titles table which have
publisher IDs matching the publisher IDs in the dbo.publishers table
will be displayed.
Only three publisher IDs in the dbo.titles table match publisher IDs in
the dbo.publishers table, so results for only those three publishers
will be displayed.
But what if you also wanted to list the publisher’s ID along with the
publisher’s name? You might think the following query would work:
SELECT title, pub_name, pub_id
FROM dbo.publishers AS p, dbo.titles AS t
WHERE p.pub_id = t.pub_id
ORDER BY title, pub_name;
Unfortunately, executing the above query results in the following
error:
Msg 209, Level 16, State 1, Line 1
Ambiguous column name 'pub_id'.
Do you see why the above query generates that error? Because
there is a pub_id in both tables, the DBMS doesn’t know which
pub_id you’re referring to. We didn’t have that problem with the first
query, because the columns “pub_name” and “title” were unique to
each table. If you select identical column names that exist in more
than one of the tables you’re querying, then you must indicate which
table you’re pulling that column from. Modify the above query as
follows to get the query to execute correctly.
Suppose you want a listing of all authors and the titles of their books.
The dbo.authors table contains author IDs and author names. The
dbo.titles table contains title IDs and titles. But neither table tells you
which author wrote which book. The table that links the two is the
dbo.titleauthor table, which contains both the author ID and the title
ID, but no author names or title names. To list all titles written by a
particular author, you will need to query all three tables.
First let’s take a look at the dbo.titleauthor table (the first 5 records
are shown to the right). This table contains an author ID and a title
ID, but no names or titles.
SELECT * FROM dbo.titleauthor;
Inner Joins
In the first example in this lesson, you were actually joining two
tables by testing whether they had matching pub_id values. This
type of query is also known as an implicit Inner Join. It returns only
rows that both tables have in common.
USE pubs
SELECT pub_name, title, [type], advance
FROM dbo.titles AS t INNER JOIN dbo.publishers AS p
ON t.pub_id = p.pub_id
AND [type] = 'popular_comp'
AND advance IS NOT NULL;
The following example displays the title and quantity of that title sold
at each store:
USE pubs
SELECT stor_id, title, qty
FROM dbo.sales AS s INNER JOIN dbo.titles AS t
ON s.title_id = t.title_id
ORDER BY title;
The following query produces the same results with an explicit Inner
Join:
SELECT au_lname, au_fname, title
FROM dbo.authors AS a
INNER JOIN dbo.titleauthor AS ta ON ta.au_id = a.au_id
INNER JOIN dbo.titles AS t ON ta.title_id = t.title_id
ORDER BY au_lname, au_fname, title;
Notice that, with the explicit Inner Joins of more than two tables, the
order of the joins is important. The table linking the other tables must
either come first or between the other tables. In this example, the
dbo.titleauthor table must be joined to the either the dbo.authors or
dbo.titles table before you can join the remaining table. For example,
the following are acceptable sequences for the joins:
FROM dbo.titleauthor AS ta
INNER JOIN dbo.authors AS a ON ta.au_id = a.au_id
INNER JOIN dbo.titles AS t ON ta.title_id = t.title_id
FROM dbo.titles AS t
INNER JOIN dbo.titleauthor AS ta ON ta.title_id = t.title_id
INNER JOIN dbo.authors AS a ON ta.au_id = a.au_id
But the following query produces an error because you haven’t yet
indicated you are querying the dbo.titleauthor table:
USE pubs
SELECT au_lname, au_fname, title
FROM dbo.authors AS a
INNER JOIN dbo.titles AS t ON ta.title_id = t.title_id
INNER JOIN dbo.titleauthor AS ta ON ta.au_id = a.au_id
The following example uses an Inner Join on more than two tables:
The above query lists the IDs of all titles having more than one
author.
You can also combine joins with the GROUP BY clause. In the
following example, displays the total number of each book sold,
summed across all stores:
USE pubs
SELECT title, SUM(qty) AS "Total Sold"
FROM dbo.sales AS s INNER JOIN dbo.titles AS t
ON s.title_id = t.title_id
GROUP BY title
ORDER BY title;
Outer Joins
The difference between an Inner Join and an Outer Join basically
boils down to the fact that an Inner Join returns only rows common to
both tables, whereas an Outer Join can return rows unique to either
the first table listed (LEFT OUTER JOIN) or the second table listed
(RIGHT OUTER JOIN).
The RIGHT OUTER JOIN below displays the same 18 rows as the
INNER JOIN because there are no titles in the title table that
correspond to those 5 publishers without titles.
In the following queries, the INNER JOIN, LEFT OUTER JOIN, and
RIGHT OUTER JOIN all produce different results:
Self Joins
A self-join joins a table to itself and compares values in one or more
columns in the table. For example, to display all authors who live in
the same city and state as the author with the author_id 213-46-8915
(last name “Green”), execute the following query. (Use the author’s
unique ID instead of his last name, just in case there is more than
one author with the same last name.)
You can also combine a self-join with either an inner or outer join.
The following example finds all titles having the same type as “The
Busy Executive’s Database Guide”, where the title has more than
one author:
USE pubs
SELECT t1.title, t1.[type]
FROM dbo.titles AS t1 INNER JOIN dbo.titles AS t2
ON t1.[type] = t2.[type]
INNER JOIN dbo.titleview AS tv
ON t1.title = tv.title
WHERE t2.title = 'The Busy Executive''s Database Guide'
AND au_ord > 1
ORDER BY title;
Using two single quotes in a row tells SQL to treat these two quotes
as one. This is called “escaping” a character. Otherwise, because
we’re using a single quote to contain the title string, if we used one
single quote for the apostrophe, then SQL would interpret the line as
follows, producing an error.
Concatenating Strings
Strings are simply several individual characters “strung” together,
hence the word “string”. While we may think of strings and
characters as the same thing, to a computer they are represented
quite differently. That is, the letter a defined as the data type CHAR
is not the same to a computer as the letter a defined as a VARCHAR
data type.
UNION
Notice that only the final query has the ending semi-colon “;”.
Unions must have at least two SELECT statements, with the UNION
operator placed between each query, and each query must specify
the same number of column names (or functions) and data type. You
can use ORDER BY after the last query if you want to sort the
results.
The following example adds another UNION. This query finds the
names of all authors living in CA, all publishers with a CA address,
and all titles published in CA. A static string is used to create the first
results column, which will display the text “Author”, “Publisher”, or
“Title” depending on whether the result is from the dbo.authors,
dbo.publishers, or dbo.titles table.
Function Description
GETDATE() Retrieves the current system date and time
DATEPART() Returns specified part of date
SELECT GETDATE();
DATEPART(part, date)
part value
year yy
month mm
day dd
hour hh
minute mi
second ss
dayofyear dy
You can display the individual parts of the current date as follows:
If you just want to compare years, we could have selected the year
with DATEPART instead of using CONVERT.
If you just want to display the date, time of publication, along with the
time in hh:mm:ss format, execute the following query:
The above query just takes the year, month, and day portions of the
DATETIME field. It does not rearrange the order in which the year,
month, and day appear. To do that we have to nest our conversions
and add the style parameter.
To convert the date and time to just the date in the formats mm-dd-yy
and mm-dd-yyyy execute the following query:
SELECT CONVERT(VARCHAR,GETDATE(),100)
AS "dd Mon yyyy (AM/PM)",
CONVERT(VARCHAR,GETDATE(),113)
AS "dd Mon yyyy (24-hr+ms)";
Creating a database
Creating, modifying, and deleting tables and views
Adding and updating records
Databases
When designing a database, you want to give careful consideration
to several factors, including the number of tables you will be adding,
the structure and data type of each column, and how much data will
be replicated from table to table. While repeating the same fields
across numerous tables may simplify some of your queries, too
much redundancy of data unnecessarily increases the size of the
database and makes adding and updating data more time
consuming, as identical columns in multiple tables must all be
updated.
Because all that redundancy makes updating records far more time
consuming than it needs to be, the pubs database has a more
efficient way to handle it. There is a table named dbo.titleauthor that
contains the au_id and the title_id. By setting foreign keys in the
authors and titles tables linking to the au_id and title_id, respectively,
in the titleauthor table, you do end up having to query three tables to
get the results, but the size of each table is substantially reduced.
Creating Databases
SQL Server Management Studio makes it easy to create a database
with the default settings. In this lesson you are going to create the
Solar_System database that will be used throughout the remainder
of the book.
When the New Database dialog opens, type Solar_System into the
Database name box, then click OK.
You will now see Solar_System listed under Databases in the Object
Explorer.
Deleting Databases
To delete a database using SQL Server Management Studio, right-
click on the name of the database, select Delete from the pop-up
menu, then click OK.
Primary Keys
In order to get accurate information from your database, there has to
be some way to uniquely identify each row in a table. This is
accomplished using a “primary key.” A primary key is also a
constraint. For more information on keys and constraints, see
Constraints.
NOTE:
If you delete a record, you cannot reuse that primary key for
any other record in the table.
The value in each primary field must be unique in the table.
You cannot change the value of a primary key once it’s been
entered.
A primary key cannot be a NULL value.
Creating Tables
To create a new table, at the minimum you will need to provide the
following information:
Optionally, you may set the primary key at the same time you create
the table (see Primary Keys).
You use the CREATE TABLE statement with the following syntax:
You will now use SQL Server Management Studio to create a table
called Planets with seven columns.
Click New Query in the toolbar, and type the following line to tell
Management Studio what database to use:
USE Solar_System
Next, enter the commands and parameters needed for creating the
table. Each of the seven fields you’ll create is assigned a data type
and either allowed or not allowed NULL values. The information for
each field is grouped together and separated by commas. (Do not
add a comma after the final column entry.)
USE Solar_System
CREATE TABLE Planets
(
PID VARCHAR(2) NOT NULL PRIMARY KEY,
Planet VARCHAR(20) NOT NULL,
Diameter_km INT NULL,
Distance_AU DECIMAL(10,2) NULL,
Distance_Mkm INT NULL,
Rotation_days DECIMAL(10,2) NULL,
Orbit_years DECIMAL(10,2) NULL,
Num_Moons INT NULL
);
Expand the (+) symbol to the left of the dbo.Planets table until you
can see all the column names.
You’ll notice the name of the table is “dbo.Planets” not “Planets”.
Since a specific user was not specified as the owner of the database
at the time it was created, the owner defaulted to SQL Server’s built-
in user account “dbo” (database owner).
Inserting Rows
At this point, we’ve created the table’s structure, but the table itself is
empty of data. To add data to the table we’ll use the INSERT INTO
command.
To insert the data into our Planets table, type the following
commands into a new query window:
NOTE:
You can copy and paste the query text from this document into your
query window. Be careful when copying text across pages, however,
as you do not want to include the page footer.
INSERT INTO dbo.Planets
VALUES ('1', 'Mercury', 4878, 0.38, 58, 58.6, 0.24, 0),
('2', 'Venus', 12100, 0.72, 108, 243.0, 0.62, 0),
('3', 'Earth', 12742, 1, 150, 1, 1, 1),
('4', 'Mars', 6792, 1.52, 228, 1.03, 1.89, 2),
('5', 'Jupiter', 139822, 5.20, 778, 0.41, 11.86, 50),
('6', 'Saturn', 116464, 9.53, 1429, 0.43, 29.46, 53),
('7', 'Uranus', 50724, 19.19, 2871, 0.75, 84.01, 27),
('8', 'Neptune', 49248, 30.06, 4504, 0.67, 164.79, 13),
('9', 'Pluto', 2324, 39.5, 5906, 6.39, 248, 5);
After executing, open a new query window and execute the following
query to view the data you just inserted into the table:
Let’s add fields named Position and Density to our Planets table:
By running the previous SELECT query on the Planets table, you will
see that the column has been added to the table. The values are all
NULL since we haven’t inserted the data for that column yet. For that
we’ll use the UPDATE command.
But now, after creating the column, you realize that you Position is
redundant, as the planet ID (PID) indicates the planet’s position from
the sun. Therefore, you want to remove (drop) the Position column.
Dropping a Column
To completely remove a column from a table, use the DROP
command with the ALTER TABLE command as follows:
Renaming a Column
If you want to rename a column you want to keep, use the system
stored procedure SP_RENAME. Be careful when renaming columns,
however. If other scripts or stored procedures reference the original
column name, these scripts and procedures will no longer work.
USE Solar_System
GO
SP_RENAME 'dbo.Planets.Density', 'Density_gpcm3', 'COLUMN'
GO
Updating Rows
The UPDATE command is used to insert or change data in a
column. You can update all rows or specific rows. The syntax is as
follows:
UPDATE table_name
SET column_name = value WHERE condition that identifies record
UPDATE dbo.Planets
SET Density_gpcm3 = 5.427 WHERE Planet ='Mercury'
UPDATE dbo.Planets
SET Density_gpcm3 = 5.243 WHERE Planet ='Venus'
UPDATE dbo.Planets
SET Density_gpcm3 = 5.513 WHERE Planet ='Earth'
UPDATE dbo.Planets
SET Density_gpcm3 = 3.934 WHERE Planet ='Mars'
UPDATE dbo.Planets
SET Density_gpcm3 = 1.326 WHERE Planet ='Jupiter'
UPDATE dbo.Planets
SET Density_gpcm3 = 0.687 WHERE Planet ='Saturn'
UPDATE dbo.Planets
SET Density_gpcm3 = 1.270 WHERE Planet ='Uranus'
UPDATE dbo.Planets
SET Density_gpcm3 = 1.638 WHERE Planet ='Neptune'
UPDATE dbo.Planets
SET Density_gpcm3 = 2.050 WHERE Planet ='Pluto';
Display the data in the table and you will see the values in the
Density_gpcm3 column have been added.
Deleting Rows
You can delete the data from all rows in a table or just specific rows
with the DELETE statement. The syntax is as follows:
If you're deleting all rows from a table, the WHERE clause can be
omitted.
Dropping A Table
To remove a table from a database, you use the DROP statement.
This destroys the table completely. The syntax is as follows:
NOTE:
Be careful about dropping tables that have dependencies (e.g.,
foreign keys, views), as this will affect those dependencies. The
easiest way to determine a table’s dependencies is to right-click on
the name of the table you wish to drop, and select View
Dependencies. You can then view a list of all objects that depend
on the table you want to drop as well as all objects on which the
table depends.
DELETE vs. DROP
Using the DELETE statement to delete all rows from a table only
removes the data contained in those rows. It empties the table but
retains the table's structure. To remove the table itself from the
database, you must use the DROP statement.
Saving a Query
For queries you will be running frequently, it's more efficient to save the
query in a file, then load that file each time you want to run the query.
Not only does this save time by not having to retype the query, but it
eliminates potential typing mistakes that could result in errors.
To save a query, first you will need to create it. You can do this using
a text-editing program like Notepad on your local computer, or you
can create the query in SQL Server Management Studio and then
save it to the location of your choice. In the following example, you'll
create and save the query from SQL Server Management Studio.
USE Solar_System
SELECT *
FROM dbo.Planets
ORDER BY Planet;
An asterisk (*) next to the name on the query tab indicates the query
has not yet been saved or changes have been made to it since it
was last saved.
When the Save File As dialog box appears, enter name and path for
the file. In this case, call it "SampleQuery.sql" and save it in the
default Projects folder. Once you've saved the file the asterisk will
disappear until you make a change.
NOTE:
All saved queries must have the extension ".sql". If your file
extensions are not displayed, you can change your current setup to
display them.
Windows XP:
Open Windows Explorer, then click Tools > Folder Options > View
Tab. In the Advanced Settings box, uncheck "Hide extensions for
known file types." (If you wish to apply this change to views of other
folders, click "Apply to All Folders" in the Folder views box.)
Windows 7:
Open Windows Explorer, then click Organize > Folder and Search
Options > View Tab. In the Advanced Settings box, uncheck "Hide
extensions for known file types." (If you wish to apply this change to
views of other folders, click "Apply to Folders" in the Folder views
box.)
Select the name of the file you want to open, then click "Open."
The contents of the file will appear in the query window. Press the F5
key or click the !Execute button to run the query.
In SQL Server Management Studio, click File > Open > File, select
the file "CreateAndPopulateMoonsTable.sql", then click "Open."
Once the contents of the file appear in the query window, execute
the query.
Since the fourth and fifth moons of Pluto that were discovered have
now been named, you’ll want to update that information in the
dbo.Moons table also:
UPDATE dbo.Moons
SET Moon = 'Kerberos'
WHERE Moon ='P4';
UPDATE dbo.Moons
SET Moon = 'Styx'
WHERE Moon ='P5';
USE Solar_System
CREATE TABLE Planet_Masses
(
PID VARCHAR(2)NOT NULL PRIMARY KEY,
Base_kg FLOAT NOT NULL,
Exponent FLOAT NOT NULL,
Gravity_mps2 FLOAT NULL
);
INSERT INTO dbo.Planet_Masses
VALUES ('1', 3.3010, 23, 3.7),
('2', 4.8673, 24, 8.87),
('3', 5.9722, 24, 9.80665),
('4', 6.4169, 23, 3.71),
('5', 1.8981, 27, 24.79),
('6', 5.6832, 26, 10.4),
('7', 8.6810, 25, 8.87),
('8', 1.0241, 26, 11.15),
('9', 1.3090, 22, 0.66);
Now that you’ve created a few tables, let's review some basic query
structures.
The following example displays the planet name and moon name for
each planet having a 5th moon:
SELECT p.Planet, m.Moon AS "5th Moon"
FROM dbo.Planets AS p, dbo.Moons AS m
WHERE p.PID = m.PID AND m.Discovery_Id = 5
;
UNION
SELECT Planet
FROM dbo.Planets
WHERE Diameter_km BETWEEN 4000 AND 6000;
Views
A view can be thought of as a virtual table. It looks like a table when
referenced, but rather than stored as a set of values like a table, it's
stored as a SELECT statement which obtains values only when
referenced by a SQL statement. At this point, it manifests itself as a
physical table, which only exists until the referencing statement has
completed execution. A view uses column names just like a table,
and can be created from one or more tables.
Views can reduce the amount of storage space that would otherwise
be allocated to redundant data. They can also increase security by
filtering out data from the underlying tables. That is, you can create a
view to contain only those columns you want visible to users (for
example, displaying an employee's name but not her social security
number).
System Views
Each database has a set of Views that are automatically created with
the database and updated as content is changed. A partial listing of
the System Views associated with the Solar_System database is
shown below:
USE Solar_System
SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE,
IS_NULLABLE, COLLATION_NAME
FROM INFORMATION_SCHEMA.COLUMNS
ORDER BY TABLE_NAME;
Creating a View
To create a View, you use the CREATE VIEW statement as follows:
Querying a View
You query a view in the same way that you query a table. For
example, to list each planet and its radius when the radius is greater
than 5000, execute the following query:
SELECT * FROM dbo.Planet_Radii
WHERE Radius > 5000;
Unfortunately, the above query only gives us the planet’s ID. To get
the planet’s name, you’ll also need to query the dbo.Planets table.
6. Delete from the Astronomers table the record you just added.
7. Drop the Astronomers table from the database.
8. Re-create the Astronomers table from the query you saved in
Exercise 1.
9. Create a View named dbo.Review5_Exercise9 that contains
the name of each planet from dbo.Planets that matches a
planet name in dbo.Moons and the name of each moon that
has a diameter greater than 500.
The resulting View will contain the 16 records shown below:
LESSON 6
In this lesson you will learn about:
Strings
Concatenation
Case-sensitivity
Substrings
Converting from one data type to another
Using data from more than one column in calculations
Strings
Just as a word in alphabet-based languages is made up of one or
more individual letters, a string (also referred to as a "literal") is made
up of a series of one or more characters. For example, the English
word "West" consists of the letters "W", "e", "s", and "t." In SQL
terminology, "West" is a string containing four characters. That is,
"West" is a string whose length is four characters. A string may
contain any character that is part of the character set used by SQL
(more about character sets in the next section).
NOTE:
Keep in mind that strings and integers are stored differently. The
string "42" is different than the number 42. For example, if you have a
column called Number with the data type VARCHAR(2), then Number
is a string. But if Number is defined with the data type INT, then
Number is an integer value. This is an important distinction, because
you can only perform arithmetic operations on a numerical data type,
not on a string. You should also be aware that the "+" operator
concatenates strings (see the following section), but adds numbers.
Collation
Collation defines the character set to use along with the sort order for
searches. You can set it at the server, database, table, and column
levels, depending on your access permissions. The COLLATE clause
is used to set the, often in conjunction with a WHERE clause to
specify whether to use case-sensitivity in a search.
COLLATE collation_name
For a list of valid collation names, execute the following query using
the system function fn_helpcollations():
SELECT name,description
FROM fn_helpcollations()
WHERE name LIKE 'SQL_Latin%';
COLLATE SQL_Latin1_General_CP1_CS_AS
Case-Sensitivity
Uppercase and lowercase characters are stored with different values
in a computer, so the character "A", for example, is not the same as
the character "a". When searching for strings, this is an important
distinction to keep in mind. If your search term is "A", a case-sensitive
search will return all "A" characters but will not return any "a"
characters. A case-insensitive search will return both "A" and "a"
characters.
Case-insensitive query:
Converting Case
There may be times, either when conducting a case-sensitive search
or setting a constraint, that you may want to change the case of a
string to all Upper or all Lower characters. To do that, you use the
UPPER() and LOWER() functions. Be aware that the conversion is
only for comparison purposes. The data itself is not changed.
where string is value in column, start is the starting position within the
string, and length is the number of characters to extract from the
starting position.
You can find the length of any string using the LEN() function, whose
syntax is as follows:
NOTE:
LEN( ) vs. LENGTH( )
The LEN( ) function is specific to Microsoft SQL Server. Oracle and
MySQL use the LENGTH( ) function.
To display every planet in the Planets table whose name begins with
the letter "M", execute the following query you can use LIKE:
USE Solar_System
SELECT Planet, PID AS "Position"
FROM dbo.Planets
WHERE Planet LIKE 'M%';
USE Solar_System
SELECT Planet, PID AS "Position"
FROM dbo.Planets
WHERE SUBSTRING(Planet, 1, 1) = 'M';
If, however, you wanted to display every planet whose name ends in
"us", you can also use LIKE or SUBSTRING( ).
USE Solar_System
SELECT Planet, PID AS "Position"
FROM dbo.Planets
WHERE SUBSTRING(Planet, LEN(Planet)-1, 2) = 'us';
CHARINDEX( )
There may be times you want to select or search for data based on
where a character is within a string. The Microsoft SQL Server
CHARINDEX( ) function, used in SELECT and WHERE statements,
allows you to do just that. The syntax for the function is as follows:
CHARINDEX(character_to_locate, string_to_search)
For example, to find all planets that have an “r” as the third character
in their name:
SELECT Planet
FROM dbo.Planets
WHERE CHARINDEX('r',Planet) = 3;
To use LIKE, you would rewrite the query as follows: (IMPORTANT:
the __ in the WHERE statement below is two successive underscore
characters.):
SELECT Planet
FROM dbo.Planets
WHERE Planet LIKE '__r%';
For the following example, you'll need to add a column called "Class"
to the Planets table. The Class field will be a two character
designation. The first character will be either a "G" or an "S",
representing Gas and Solid, respectively. The second character will
be either an "L" or an "M", representing an axial tilt of less than 90
degrees or more than 90 degrees, respectively.
USE Solar_System
ALTER TABLE dbo.Planets
ADD Class CHAR(2) NULL;
USE Solar_System
UPDATE dbo.Planets
SET Class = 'SL' WHERE Planet = 'Mercury'
UPDATE dbo.Planets
SET Class = 'SM' WHERE Planet = 'Venus'
UPDATE dbo.Planets
SET Class = 'SL' WHERE Planet = 'Earth'
UPDATE dbo.Planets
SET Class = 'SL' WHERE Planet = 'Mars'
UPDATE dbo.Planets
SET Class = 'GL' WHERE Planet ='Jupiter'
UPDATE dbo.Planets
SET Class = 'GL' WHERE Planet ='Saturn'
UPDATE dbo.Planets
SET Class = 'GM' WHERE Planet ='Uranus'
UPDATE dbo.Planets
SET Class = 'GL' WHERE Planet ='Neptune'
UPDATE dbo.Planets
SET Class = 'SM' WHERE Planet ='Pluto'
;
USE Solar_System
SELECT Planet, Class, CHARINDEX('S', Class) AS "Index of 'S'"
FROM dbo.Planets
WHERE CHARINDEX('S', Class) = 1
ORDER BY PID;
USE Solar_System
SELECT Planet, Class
FROM dbo.Planets
WHERE CLASS LIKE 'S_'
ORDER BY PID;
USE Solar_System
SELECT Planet, CHARINDEX('p', Planet) AS "Index of 'p'"
FROM dbo.Planets
WHERE CHARINDEX('p', Planet) > 0
ORDER BY Planet;
USE Solar_System
SELECT Planet, CHARINDEX('p', Planet) AS "Index of 'p'"
FROM dbo.Planets
WHERE Planet LIKE '%p%'
ORDER BY Planet;
USE Solar_System
SELECT 'Planet' AS "Planet/Moon",
Planet AS "Name"
FROM dbo.Planets
UNION
where name of moon is the column Moon and distance is the column
Distance_km.
If you tried the following query, you would receive an error, because
Moon and Distance_km are two different data types:
To produce the desired results, you must convert the distance to the
VARCHAR data type. Modify the preceding query as follows:
If you want to include the planet’s actual name, you will need to
query both the dbo.Moons and dbo.Planets tables as follows:
USE Solar_System
SELECT Planet, Base_kg * POWER(10.0,Exponent) AS "Mass_kg"
FROM dbo.Planets AS p, dbo.Planet_Masses AS pm
WHERE p.PID = pm.PID;
Let’s dissect the SELECT statement from our query, starting with this
term:
POWER(10.0, Exponent)
The Power function has the following syntax:
Power(expression, exponent)
SELECT Planet,
CONVERT(FLOAT,(Base_kg * Power(10.0, Exponent)),0) AS
Mass_kg
FROM dbo.Planets AS p, dbo.Planet_Masses AS pm
WHERE p.PID = pm.PID;
GO
USE Solar_System
SELECT PID, MIN(Distance_km)
AS Distance_from_Closest_Moon
FROM dbo.Moons
GROUP BY PID;
To display the planet name associated with each PID, you need
query both the dbo.Planets and dbo.Moons tables. The example
below revises the above query, using an INNER JOIN so that the
Planet name is retrieved:
USE Solar_System
SELECT p.PID, Planet, MIN(Distance_km)
AS Distance_from_Closest_Moon
FROM dbo.Planets AS p INNER JOIN dbo.Moons AS m
ON p.PID = m.PID
GROUP BY p.PID, Planet;
You can also use the above query to create an additional view as
follows:
CREATE VIEW dbo.View_Closest_Moons
AS
SELECT p.PID, Planet, MIN(Distance_km)
AS Distance_from_Closest_Moon
FROM dbo.Planets AS p INNER JOIN dbo.Moons AS m
ON p.PID = m.PID
GROUP BY p.PID, Planet;
GO
Review 6
1. Display the first name, the length of the first name, the last
name, and the length of the last name for each astronomer in
the dbo.Astronomers View you created in Review 5. Be sure
to use an alias for the calculated column names.
USE pubs
SELECT a1.au_lname, a1.au_fname, a1.city, a1.[state]
FROM dbo.authors AS a1, dbo.authors AS a2
WHERE a1.city = a2.city
AND a2.au_lname = 'Green';
USE Solar_System
SELECT Moon, Diameter_km
FROM dbo.Moons
WHERE Diameter_km >
(SELECT Diameter_km
FROM dbo.Planets
WHERE Planet = 'Mercury');
The subquery is evaluated first, returning the value 4878 to the outer
query. The outer query then compares the diameters of all moons to
that value, then displays the names and diameters of the three
moons having diameters greater than 4878.
SELECT Planet
FROM dbo.Planets
WHERE NOT PID IN
(SELECT PID FROM dbo.Moons);
To get the actual names of the planets, you need to query the
dbo.Planets table also:
SELECT Planet
FROM dbo.Planet_Masses AS pm,
dbo.Planets AS p
WHERE Gravity_mps2 >
(SELECT Gravity_mps2
FROM dbo.Planet_Masses
WHERE PID = '3')
AND pm.PID = p.PID ;
USE pubs
SELECT title, price,
price/(SELECT MAX(price) FROM dbo.titles) * 100
AS "% of Max Price"
FROM dbo.titles
WHERE price IS NOT NULL;
Using a JOIN will not work because a join is run as a single query,
with all column values, functions, and filtering criteria evaluated at
the same time. Subqueries are evaluated in succession (innermost
to outermost), with the results of each subquery passed as input to
the next higher query.
To display the planet name instead of the PID, modify the previous
query as follows:
SELECT Planet,
Gravity_mps2,
(SELECT pm.Gravity_mps2/MIN(Gravity_mps2)
FROM dbo.Planet_Masses) AS "Ratio to Lightest",
(SELECT pm.Gravity_mps2/MAX(Gravity_mps2)
FROM dbo.Planet_Masses) AS "Ratio to Heaviest"
FROM dbo.Planet_Masses AS pm, dbo.Planets AS p
WHERE pm.PID = p.PID ;
USE Solar_System
SELECT Moon
FROM dbo.Moons
WHERE SUBSTRING(Moon,1,1)
IN (SELECT SUBSTRING(Planet,1,1) FROM dbo.Planets);
First the SELECT statement in the subquery was evaluated,
returning the first character in each planet in the Planet column of
the Planets table. Then the first character in each moon name in the
Moons column of the Moons table was compared to the set of
characters returned by the subquery. The above query then returns
59 rows displaying all moons that begin with the letters "E", "J", "M",
"N", "P", "S", and "U".
You could have written the query without the subquery, but that
would have required you to know the contents of Planets table. In
this case, it would have been easy, but usually you don't know what
all the values are in a column in advance. This is another reason
subqueries are so useful.
The CASE Statement
A CASE statement is an efficient way to select, filter, or sort
columns. There are two types of CASE statements: Simple and
Searched. Both can be used with the various SQL statements and
clause, including:
SELECT
WHERE
HAVING
ORDER BY
INSERT
UPDATE
SET
DELETE
This lesson will focus on using the CASE statement with the
SELECT and ORDER BY statements.
CASE expression_to_compare_with_when_expressions
WHEN expression1 THEN Result1
WHEN expression2 THEN Result2
.
.
.
WHEN expressionN THEN ResultN
ELSE Result_for_all_other_conditions
END
For example, to display a different value for each record of the Class
column based on the original column value, execute the following
query:
USE Solar_System
SELECT Planet, CASE Class
WHEN 'SL' THEN 'Solid, tilt<90'
WHEN 'SM' THEN 'Solid, tilt>90'
WHEN 'GL' THEN 'Gas, tilt<90'
WHEN 'GM' THEN 'Gas, tilt>90'
END
FROM dbo.Planets;
CASE
WHEN boolean_expression1 THEN Result1
WHEN boolean_expression2 THEN Result2
.
.
.
WHEN boolean_expressionN THEN ResultN
ELSE Result_for_all_other_conditions
END
USE Solar_System
SELECT * FROM dbo.Planets
ORDER BY CASE
WHEN CLASS LIKE 'S%' THEN Density_gpcm3
WHEN CLASS LIKE 'G%' THEN Diameter_km
END;
When displaying the dbo.Planets table with just the statement
“SELECT * FROM dbo.Planets”, you get the following results:
USE Solar_System
SELECT Moon, Diameter=CASE
WHEN Diameter_km > (SELECT Diameter_km
FROM dbo.Planets
WHERE Planet = 'Mercury')
THEN Larger than Mercury'
ELSE 'Smaller than Mercury'
END
FROM dbo.Moons
ORDER BY Diameter_km DESC;
Rename a column
USE Solar_System
GO
SP_RENAME 'table_name.old_col_name', 'new_col_name', 'COLUMN'
GO
DBCC CHECKTABLE
DataBase Consistency Check (DBCC) CHECKTABLE looks for
problems in a specific table and also returns the number of rows in
the table. For example, the following query checks the table
dbo.Moons for errors:
DBCC CHECKTABLE ("dbo.Moons");
sp_MSforeachtable
The sp_MSforeachtable procedure accepts parameters that allow
you to retrieve information such as the name of each table in a
database, the number of rows in specified tables, and so on. In lieu
of specifying a table name, you can use “?” as a type of wildcard to
mean all tables.
EXEC sp_MSforeachtable
'SELECT "?" AS TableName, COUNT(*) AS NumberOfRows FROM
?';
END
GO
The first procedure we'll create is a query that displays all planets
with moons, the name of their closest moon, and the distance from
that moon. Since it's a query that uses nested subqueries and
grouping, and you've been instructed that you'll run this query often,
creating it as a stored procedure will save you a lot of time and effort
in the long run.
Before creating the procedure, however, let’s look at the query itself
step-by-step.
The first part of the query, shown below, displays two columns: (1)
the name of each planet in dbo.Planets with matching PIDs in
dbo.Moons and (2) the minimum value of Distance_km for each PID
(because we’re grouping by PID).
USE Solar_System
SELECT
--Subquery #1
--First column Planet with alias "Name of Planet"
--Finds all PIDs in dbo.Planets with matching PIDs
--in dbo.Moons
(SELECT Planet
FROM dbo.Planets AS p1
WHERE m1.PID = p1.PID) AS "Name of Planet",
--Subquery #2
--Second column MIN(Distance_km) with alias
--"Distance to Moon(km)"
MIN(m1.Distance_km) AS "Distance to Closest Moon (km)"
FROM dbo.Moons AS m1
GROUP BY PID;
Next we need to find the name of the moon in each PID grouping
whose Distance_km equals the minimum distance we retrieved in
the first part of the query. To do that, you’ll add a third subquery just
before the line “FROM dbo.Moons AS m1”. (Don’t forget to add a
comma after the second subquery.)
USE Solar_System
SELECT
--Subquery #1
--First column Planet with alias "Name of Planet"
--Finds all PIDs in dbo.Planets with matching PIDs
--in dbo.Moons
(SELECT Planet
FROM dbo.Planets AS p1
WHERE m1.PID = p1.PID) AS "Name of Planet",
--Subquery #2
--Second column MIN(Distance_km) with alias
--"Distance to Moon(km)"
MIN(m1.Distance_km) AS "Distance to Closest Moon (km)",
--Subquery #3
--Third column Moon with alias "Name of Closest Moon"
--Retrieves name of moon in dbo.Moons whose distance
--(for each PID) equals the minimum distance for that
--PID (retrieved in subquery #2)
(SELECT Moon FROM dbo.Moons
WHERE Distance_km IN (MIN(m1.Distance_km)))
AS "Name of Closest Moon"
FROM dbo.Moons AS m1
GROUP BY PID;
To turn this query into a stored procedure, insert the following text at
the beginning of the query:
END
GO
(SELECT Planet
FROM dbo.Planets AS p1
WHERE m1.PID = p1.PID) AS "Name of Planet",
FROM dbo.Moons AS m1
GROUP BY PID;
END
GO
To run the stored procedure, open a new query window and execute
the following statement:
EXEC dbo.sp_find_closest;
When you run the above query, the “SELECT @z” statement
displays the contents of the variable @z in the results window.
USE Solar_System
SELECT Planet, Diameter_km
FROM dbo.Planets
WHERE Diameter_km <= (SELECT Diameter_km FROM
dbo.Planets
WHERE Planet = 'Earth')
ORDER BY Diameter_km DESC;
You get the same results by storing the results of the select
statement from the subquery in a variable, then using the value of
that variable later in your query:
USE Solar_System
DECLARE @earth INT = (SELECT Diameter_km FROM
dbo.Planets
WHERE Planet = 'Earth')
SELECT Planet, Diameter_km
FROM dbo.Planets
WHERE Diameter_km <= @earth
ORDER BY Diameter_km DESC;
Or, you could store the results of the two subqueries in two variables,
then use those variables in the WHERE clause and get the same
results:
Step 2. In the Save as type box, select All files (*.*), then name the
file test.htm. (You must use the .htm extension NOT .txt. Otherwise
the browser cannot display the HTML content.)
SELECT @tableHTML
END
GO
Executing the above query creates and saves the stored procedure.
To run the procedure, open a new query window and execute the
following code:
EXEC dbo.sp_planet_categories;
You will see the following results:
If you don't know the exact name of the procedure, it can be found in
the Stored Procedures subfolder of the Programmability folder under
your database name in the Object Explorer.
Review 7
1. Using a subquery in a WHERE clause, display the name,
diameter, and moon ID of each moon having a diameter
greater than 50% of that of Mars.
Constraint Description
PRIMARY Used to uniquely identify a row. A table may
KEY have only one Primary Key.
FOREIGN A column in one table that references a
KEY Primary Key in another table. A table may
contain more than one Foreign Key.
UNIQUE Forces a value in a column to be unique
(Primary Keys automatically have this
constraint).
NOT NULL Ensures that a value must be entered in that
column for each record.
CHECK Checks the validity of values based on
specified criteria.
Setting Constraints
Constraints can be set at the time a table is created or added later.
This section provides examples of both methods.
The syntax of the CONSTRAINT statement is:
CONSTRAINT constraint_name constraint conditions
UNIQUE Constraints
A Unique constraint declares that the data in a particular column
must be unique in that column. All Primary keys are Unique, but not
every column with the Unique constraint applied is necessarily a
Primary key.
CHECK Constraints
A Check constraint validates data as it is entered. Examples of
CHECK constraints include ensuring a value must be greater than
zero, be within a certain range, or start with an uppercase letter.
The new table will be populated with the first three records from
dbo.Planets.
USE Solar_System
CREATE TABLE Sample_Constraints
(
Pname VARCHAR(20) NOT NULL,
Position VARCHAR(2) NOT NULL,
Year_length FLOAT NULL,
Distance_AU FLOAT NOT NULL,
CONSTRAINT sample_constraints_PK
PRIMARY KEY(Pname),
CONSTRAINT sample_constraints_FK
FOREIGN KEY(Position)
REFERENCES dbo.Planets(PID),
CONSTRAINT sample_constraints_UQ_position
UNIQUE(Position),
CONSTRAINT sample_constraints_UQ_distance
UNIQUE(Distance_AU),
CONSTRAINT sample_constraints_ck_position
CHECK(Position > 0),
CONSTRAINT sample_constraints_ck_year
CHECK(Year_length > 0 AND Year_length <= 250),
CONSTRAINT sample_constraints_ck_distance
CHECK(Distance_AU > 0)
);
Now execute the following query to view the contents of the new
Sample_Constraints table:
Testing Constraints
To test the validity of data entered into the table you just created,
we'll try to enter invalid data.
Dropping a Constraint
Whenever you want to remove a constraint you must do so using the
DROP statement in conjunction with an ALTER TABLE statement.
You will receive the following error message because we are trying
to set a constraint that does not allow values in the Pname column to
begin with the character "A" but it already contains the value "Ares".
Msg 547, Level 16, State 0, Line 1
The ALTER TABLE statement conflicted with the CHECK constraint sample_constraints_ck_Pname". The
conflict occurred in database "Solar_System", table "dbo.Sample_Constraints", column 'Pname'.
To solve this problem, we can add the constraint for future entries,
add the WITH NOCHECK option. This will not check the current
entries before trying to add the constraint.
USE Solar_System
CREATE TABLE Sample_Constraints_2
(
PID VARCHAR(2) NOT NULL PRIMARY KEY,
Pname VARCHAR(20) NOT NULL,
Position FLOAT NOT NULL
);
You will see that the characters "2m" are accepted as values for the
PID field, since we haven't told such combinations are not allowed.
To understand why this works, let's dissect the query that created the
constraint, starting with the ALTER TABLE statement. You'll notice
that we added the WITH NOCHECK option at the end. This is
because there are already values in our table which would violate
the constraints we're setting, and we want to ignore those for now.
But if you switch the positions of the "3" and the "m", the data is
accepted.
Now drop the CHECK constraint you created and add one that will
ensure the entry of only uppercase values in the first position of PID.
ALTER TABLE dbo.Sample_Constraints_2
DROP CONSTRAINT sample_constraints_2_PID_CK;
To re-create the constraint to include case-sensitivity, execute the
following query:
Or you can use the UNICODE function with CHECK statement. For
example, you could replace the first SUBSTRING/COLLATE/LIKE
sequence
(SUBSTRING(PID, 1, 1) COLLATE SQL_Latin1_General_CP1_CS_AS
LIKE '[ABCDEFGHIJKLMNOPQRSTUVWXYZ]')
The Unicode value for uppercase A is 65, and the value for
uppercase Z is 90.
You can also shorten the above A through Z and 0 through 0 ranges
to [A-Z] and [0-9], respectively.
But if you use an uppercase character in the first position of PID, the
data is accepted.
9. Select the Server Name (you will probably want to keep the
preselected name, which should be the server you're logged
into).
10. In the Authentication group box, select Use Windows
Authentication if it's not already selected.
11. The Database name you're working with should be
preselected, or you may choose a different database at this
time.
12. Click Next.
13. In the Specify Table Copy or Query dialog box, select Copy
data from one or more tables or views.
14. Click Next.
15. In the Select Source Tables and Views dialog box, select
TestImportData$ as the source, then click in the Destination
column and delete the $ at the end of the name as shown
below. (You are importing the sheet named TestImportData$
but the table name in SQL Server will now be
dbo.TestImportData.)
Now follow the same procedure as earlier for importing the data with
the following changes:
The only progress line that’s should look different is the one that
shows the number of rows transferred (you transferred 3 rows the
first time).
Creating an Index
There are four types of indexes you can create:
Single-column index
Unique index
Composite index
Implicit index (column index automatically created at the
time the table is created, such as for Primary keys and
Unique constraints)
Clustered indexes determine the physical order of the rows, i.e., the
table is resorted in the order of the indexing criteria. You can have
only one clustered index per table.
Non-clustered indexes, the table rows are not reordered. Instead, the
index is a pointer to the location of the data, which can be in any
order. All the indexes created in this lesson will be typical non-
clustered indexes.
Single-Column Index
This type of index is used frequently in cases where a WHERE
clause is repeatedly used to retrieve an ID of some sort. Single-
column indexes are also frequently used on Foreign key columns.
USE Solar_System
CREATE INDEX Pname_IDX
ON Sample_Constraints (Pname);
Refresh your table in the Object Explorer, expand the Indexes folder
under the table name, and you'll see the name of the index you just
created. To see information about the index, right click on the index
name, then select Properties.
Unique Index
This type of index is the same as a single-column index, with the
added requirement that all values in that column must be unique
(e.g., a social security number, an employee ID, etc.).
Composite Index
This type of index is based on two or more columns that are typically
used together in WHERE and/or ORDER BY clauses. For example,
if, from the titles table in the pubs database, you often sorted by
title_id, pub_id, you could create a composite index on those
columns. If, in the authors table you often checked for specific values
of au_lname and au_fname, a composite index on those columns
might decrease your search time.
Deleting an Index
To delete an index, use the DROP INDEX command as follows:
or
USE Solar_System
ALTER TABLE dbo.Moons
ADD CONSTRAINT fk_moons
FOREIGN KEY(PID) REFERENCES dbo.Planets(PID);
Now if you try to delete the planet Pluto from the dbo.Planets table:
DELETE FROM dbo.Planets
WHERE PID = '9';
You will receive the following error because the PID column in
dbo.Moons is “linked” to a column in the dbo.Planets table:
Pluto would not be deleted from the dbo. Planets table due to an
error, yet it would be deleted from both the dbo.Moons and
dbo.Planet_Masses tables. This would destroy referential integrity
among the tables.
To maintain referential integrity, place your statements within a
Transaction, test for errors and, if found, ROLLBACK the Transaction
without committing it.
COMMIT
RETURN
ERR_HANDLER:
PRINT '*** Your transaction is being rolled back due to an error ***'
ROLLBACK TRANSACTION
To achieve the desired results, make sure you delete Pluto from the
dbo.Planets table after you’ve deleted it from the dbo.Moons table.
The revised Transaction follows:
USE Solar_System
BEGIN TRANSACTION
COMMIT
RETURN
ERR_HANDLER:
PRINT '*** Your transaction is being rolled back due to an error ***'
ROLLBACK TRANSACTION
Review 8
PREREQUISITES:
Before you begin this review, make sure you have created the
C:\SQL_ADV folder on your computer.
1. Add a CHECK constraint to the Sample_Constraints table
that does not allow the column Pname to contain any of the
characters 0 through 9 in any position.
2. Create a table in Excel with columns headers ID (this will be
your primary key), L_name, F_name, Gender, and
Profession. Insert at least 5 rows of data (you may leave any
column blank except ID and L_name). Save the Excel file in
your C:\SQL_ADV folder as Review8_Exercise1.xlsx.
SAMPLE SPREADSHEET:
3. Import the Excel data from Exercise 2 into SQL. Your table
name will be dbo.StarGate. You can leave the sheet name
as the default or name it something else. To import the data,
you may use either a distributed query or the Import Data
Feature in SQL Server Management Studio
4. Alter the ID column in the dbo.StarGate table so that the data
type is INT and NULL values are not allowed.
5. Execute the following as a single Transaction (include error
checking and an error handling section):
1. Alter the dbo.StarGate table to add a PRIMARY KEY
constraint on the ID column.
2. Try to insert the following record (HINT: you need an
error check after this statement):
INSERT INTO dbo.StarGate
VALUES (1,'Mitchell', 'Cameron','M','Farscape Refugee')
3. Create a Composite Index on the L_name and F_name
columns in the table you imported in Exercise #3.
4. Display the contents of the newly created table.
After you open SQL Server Management Studio, you will see a
“Connect to Server” dialog box similar to the following:
Click Connect and you will see a screen similar to the following:
Now you’re ready to install the pubs database.
To see a list of tables in the pubs database, click the plus (+) symbol
to the left of pubs, then click the plus symbol to the left of Tables.
To see a list of column names and their assigned data types, click
the plus symbol to the left of any table name, then click the plus
symbol to the left of Columns.
To save a query, right click on the tab showing the current query
name, select “Save SQLQuery1.sql” then save it as the name you
choose in whatever location you’ve set up to hold your query files.
Appendix B: Tables and
Columns in the Pubs Database
Below is a screen shot from SQL Server Management Studio
showing a portion of the pubs database with the columns information
for the authors, titleauthor, and titles tables expanded, along with a
sample query:
To see a list of all table names and their fields, execute the following
query:
USE pubs
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS;
Appendix C: Solutions to
Review Exercises
Review 1 Solutions
1. Using the pubs database, query the dbo.authors table to
display all authors’ first and last names in ascending order by
last name, then by first name.
SOLUTION:
USE pubs
SELECT au_fname, au_lname
FROM dbo.authors
ORDER BY au_lname, au_fname;
2. Using the pubs database, query the dbo.authors table to
display the first and last names of all authors whose last
name begins with the letter “G”.
SOLUTION:
SELECT au_fname, au_lname
FROM dbo.authors
WHERE au_lname LIKE 'G%';
SELECT title
FROM dbo.titles
WHERE NOT title LIKE 'T%'
ORDER BY title;
7. Using the pubs database, query the dbo.titles table to display
the title and price for all books whose price is 2.99, 14.99, or
19.99.
SELECT title, price
FROM dbo.titles
WHERE price IN (2.99, 14.99, 19.99)
ORDER BY price;
3. Using the pubs database, query the dbo.titles table to list the
book type and the number of publishers that carry each type
of book, ignoring any title with the type UNDECIDED. Use the
column alias “Num. pubs publishing this type” for your
calculated value.
SOLUTION:
SELECT [type],
COUNT(pub_id) AS "Num. pubs publishing this type"
FROM dbo.titles
GROUP BY [type]
HAVING [type] <> 'UNDECIDED';
SOLUTION:
SELECT pub_name, royalty
FROM dbo.publishers, dbo.titles
WHERE dbo.publishers.pub_id = dbo.titles.pub_id
AND royalty > 10;
4. Using either an implicit Inner Join or an explicit Inner Join,
query the dbo.publishers and dbo.titles tables in the pubs
database to list all publishers who pay their authors a royalty
higher than 10 percent, but list each publisher’s name only
once. Use the column alias “Pubs with high royalty” for the
publisher name column.
SOLUTION:
SELECT DISTINCT pub_name AS "Pubs with high royalty"
FROM dbo.publishers, dbo.titles
WHERE dbo.publishers.pub_id = dbo.titles.pub_id
AND royalty > 10;
or
Column Alias
title Book Title
average lorangeAverage Low
average hirangeAverage High
SOLUTION:
SELECT title AS "Book Title",
AVG(lorange) AS "Average Low",
AVG(hirange) AS "Average High"
FROM dbo.titles AS t INNER JOIN dbo.roysched AS r
ON t.title_id = r.title_id
GROUP BY title;
SOLUTION:
SELECT DISTINCT title, t.royalty
FROM dbo.titles AS t LEFT OUTER JOIN dbo.roysched AS r
ON t.title_id = r.title_id
ORDER BY title;
With the LEFT OUTER JOIN, the two titles from the titles table
that have no corresponding titlle_id in royalty schedule table are
also displayed.
SOLUTION:
SELECT au_lname, title, royalty
FROM dbo.authors AS a,
dbo.titles AS t, dbo.titleauthor AS ta
WHERE a.au_id = ta.au_id AND t.title_id = ta.title_id
AND NOT royalty IS NULL
ORDER BY au_lname, title;
UNION
SOLUTION:
SOLUTION:
SELECT lname,
CONVERT(VARCHAR(8), hire_date, 10) AS "Hire Date"
FROM dbo.employee
WHERE DATEPART(yy, hire_date) > 1992
ORDER BY hire_date DESC;
SOLUTION:
SELECT lname,
DATEPART(yy, hire_date) AS "Year Hired"
FROM dbo.employee
WHERE lname LIKE 'L%'
ORDER BY lname;
6. Using the pubs database, query the dbo.employee table to
display the last name of every employee whose last name
begins with the letter “L”, and the hire date in three separate
columns—one for year, one for month, and one for day of
year. Use “Year Hired”, “Month Hired”, and “Days into Year
Hired”, respectively, as the column names for the date parts.
Sort in ascending order by employee’s last name.
SOLUTION:
SELECT lname,
DATEPART(yy, hire_date) AS "Year Hired",
DATEPART(mm, hire_date) AS "Month Hired",
DATEPART(dy, hire_date) AS "Days into Year Hired"
FROM dbo.employee
WHERE lname LIKE 'L%'
ORDER BY lname;
Review 5 Solutions
1. Create a table named Astronomers with the following column
names and data types. In the same query insert the values
into the table. (Don ' t delete this table, you will be using to it
throughout this review.) Save this query as
Review5Exercise1.sql in the default “Projects” folder;
you will need to execute it again in Exercise 7 of this
review and in Exercise 1 of Review 6.
Fields
AsId—This is the Astronomer ID. Data type: CHAR(2). Use as
the primary key.
Fname—Astronomer ' s first name. Data type: VARCHAR(20).
This field may contain a NULL value.
Lname—Astronomer ' s last name. Same data type as Fname.
This field cannot contain a NULL value.
Born—Date the astronomer was born. Data type: DATE. This field
may contain a NULL value.
Died—Date the astronomer died. Data type: DATE. This field may
contain a NULL value.
SOLUTION:
USE Solar_System
SOLUTION:
USE Solar_System
UPDATE dbo.Astronomers
SET Object_Discovered ='Uranus'
WHERE Lname ='Herschel';
UPDATE dbo.Astronomers
SET Object_Discovered ='Pluto'
WHERE Lname ='Tombaugh';
4. Add a record to the Astronomer ' s table. (Remember to enter
dates as a string in the format YYYY-MM-DD.)
Values
AsId—3
Fname—Galileo
Lname—Galilei
Born—February 15, 1564
Died—January 8, 1642
Object_Discovered—Io
SOLUTION:
USE Solar_System
INSERT INTO dbo.Astronomers
VALUES ('03','Galileo','Galilei','2/15/1564','1/8/1642','Io');
SOLUTION:
CREATE VIEW dbo.View_Astronomers
AS
SELECT AsId, Fname, Lname
FROM dbo.Astronomers
GO
You can use column in the WHERE clause that uniquely identifies
the record to be deleted. In this example, we knew there was only
one record containing the first name Galileo. To be certain you are
deleting the correct record from a table with a large number of
records, either use the Primary Key column as the identifier, or
multiple criteria such as first and last names (for example,
WHERE Fname = ' firstname ' AND Lname = ' lastname ' ).
Notice that the View you created from this table appears to
remain, however if you try to execute SELECT * FROM
dbo.View.Astronomers, you will receive the following error:
SOLUTION:
USE Solar_System
SELECT Moon, Diameter_km
FROM dbo.Moons
WHERE Diameter_km >
(SELECT Diameter_km * .5
FROM dbo.Planets
WHERE Planet = 'Mars')
;
SOLUTION:
USE Solar_System
SELECT Planet, Moons=CASE Num_Moons
WHEN 0 THEN 'No'
ELSE 'YES'
END
FROM dbo.Planets;
USE Solar_System
SELECT Planet, Weight=CASE
WHEN pm.Weight_lb > (SELECT Weight_lb
FROM dbo.Planet_Masses
WHERE PID = '3')
THEN 'You weigh more'
WHEN pm.Weight_lb < (SELECT Weight_lb
FROM dbo.Planet_Masses
WHERE PID = '3')
THEN 'You weigh less'
ELSE 'Weight unchanged'
END
FROM dbo.Planets AS p, dbo.Planet_Masses AS pm
WHERE p.PID = pm.PID
ORDER BY p.PID;
5. In Lesson 1 you were introduced to system views that
allowed you to retrieve a copious amounts of data about
tables, columns, etc. using INFORMATION_SCHEMA
subsets. For this exercise, you will create a stored procedure
called sp_review_7_3 that retrieves the following information
from the Solar_System database in three successive queries:
Query #1: Display column constraints (HINT: Query
CONSTRAINT_COLUMN_USAGE from
INFORMATION.SCHEMA.CONSTRAINTS.)
Query #2: Display table information. (HINT: Query TABLES from
INFORMATION.SCHEMA.CONSTRAINTS.)
Query #3: Execute the sp_tables procedure, retrieving only the
information related to
tables owned by the dbo user.
SOLUTION:
CREATE PROCEDURE sp_review_7_3
AS
BEGIN
SELECT *
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE;
SELECT *
FROM INFORMATION_SCHEMA.TABLES;
SOLUTION:
SOLUTION (The symbol prefaces each line with a change; changed lines also
in red text):
CREATE PROCEDURE sp_planet_sizes
AS
BEGIN
DECLARE @tableHTML nVarchar(max)
DECLARE @subject nVarchar(max)
SET @subject = 'Planetary Report'
SET @tableHTML =
N'<html><head><title>Query Results</title></head><body>' +
N'<table width="75%" style="color: red; border: 1 solid black; padding: 1; text-
align: center">' +
N'<caption style="font-size: 24pt">Planets With Diameter Greater Than
Earth</caption>' +
N'<tr><th> Planet </th><th> Diameter(Km) </th><th> Distance(AU) </th>' +
N'<th> Distance(MKm) </th><th> Rotation(days) </th><th> Orbit(years) </th>
<th> # Moons </th><th> Position </th>'+
N'</tr>' +
CAST ( ( SELECT td = Planet, '',
td = Diameter_km, '',
td = Distance_AU, '',
td = Distance_Mkm, '',
td = Rotation_days, '',
td = Orbit_years, '',
td = Moons, '',
td = Position, ''
FROM dbo.Planets
WHERE Diameter_km >
(SELECT Diameter_km FROM dbo.Planets
WHERE Planet = ‘Earth')
ORDER BY Diameter_km
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
N'</table>' +
COMMIT
RETURN
EPIC_FAIL:
PRINT '*** Your transaction is being rolled back due to an error ***'
ROLLBACK TRANSACTION
Running the above query produces the following error
messages because you are trying to use the number 1 as a
Primary Key more than once:
6. Fix the error in the Transaction from Exercise 5 and re-run the
query.
SOLUTION:
In the Transaction above, change the 1 to 6 in the INSERT INTO
statement:
INSERT INTO dbo.StarGate
VALUES (6,'Mitchell', 'Cameron','M','Farscape Refugee')
1. Go to http://www.charlotteswebworld.com/downloads.html.
2. Right-click on the Saved Queries link, then save the zip file to the
default Projects folder or the folder of your choice.
NOTE:
C:\Users\<your user name>\Documents\SQL Server Management
Studio\Projects
is the default folder used by SQL Server Management Studio to save and
open files.
3. Navigate to the folder where you saved the file and unzip the file. You
will then be able to open and execute the saved queries in SQL
Server Management Studio.
CreateAndPopulatePlanetsTable.sql
USE Solar_System
CREATE TABLE Planets
(
PID CHAR(1) NOT NULL PRIMARY KEY,
Planet VARCHAR(20) NOT NULL,
Diameter_km INT NULL,
Distance_AU DECIMAL(10,2) NULL,
Distance_Mkm INT NULL,
Rotation_days DECIMAL(10,2) NULL,
Orbit_years DECIMAL(10,2) NULL,
Num_Moons INT NULL
);
UpdatePlanetsTable.sql
/* Run the alter table query before trying to update, since
you have to add the column before you add the data:
*/
UPDATE dbo.Planets
SET Density_gpcm3 = 5.427 WHERE Planet ='Mercury'
UPDATE dbo.Planets
SET Density_gpcm3 = 5.243 WHERE Planet ='Venus'
UPDATE dbo.Planets
SET Density_gpcm3 = 5.513 WHERE Planet ='Earth'
UPDATE dbo.Planets
SET Density_gpcm3 = 3.934 WHERE Planet ='Mars'
UPDATE dbo.Planets
SET Density_gpcm3 = 1.326 WHERE Planet ='Jupiter'
UPDATE dbo.Planets
SET Density_gpcm3 = 0.687 WHERE Planet ='Saturn'
UPDATE dbo.Planets
SET Density_gpcm3 = 1.270 WHERE Planet ='Uranus'
UPDATE dbo.Planets
SET Density_gpcm3 = 1.638 WHERE Planet ='Neptune'
UPDATE dbo.Planets
SET Density_gpcm3 = 2.050 WHERE Planet ='Pluto';
UpdatePlanetsTable-2.sql
/* Execute this query separately before updating the table.
USE Solar_System
ALTER TABLE dbo.Planets
ADD Class CHAR(2) NULL;
*/
USE Solar_System
UPDATE dbo.Planets
SET Class = 'SL' WHERE Planet = 'Mercury'
UPDATE dbo.Planets
SET Class = 'SM' WHERE Planet = 'Venus'
UPDATE dbo.Planets
SET Class = 'SL' WHERE Planet = 'Earth'
UPDATE dbo.Planets
SET Class = 'SL' WHERE Planet = 'Mars'
UPDATE dbo.Planets
SET Class = 'GL' WHERE Planet ='Jupiter'
UPDATE dbo.Planets
SET Class = 'GL' WHERE Planet ='Saturn'
UPDATE dbo.Planets
SET Class = 'GM' WHERE Planet ='Uranus'
UPDATE dbo.Planets
SET Class = 'GL' WHERE Planet ='Neptune'
UPDATE dbo.Planets
SET Class = 'SM' WHERE Planet ='Pluto';
CreateAndPopulateMoonsTable.sql
USE Solar_System
CREATE TABLE Moons
(
Moon VARCHAR(20)NOT NULL PRIMARY KEY,
Diameter_km DECIMAL(10,2 )NULL,
PID CHAR(1) NOT NULL,
Discovery_Id INT NULL,
Distance_km INT NULL
);
UpdateMoonsTable.sql
USE Solar_System
UPDATE dbo.Moons
SET Diameter_km = 2,
Distance_km = 23800000
WHERE Moon ='Cyllene';
UPDATE dbo.Moons
SET Moon = 'Kerberos'
WHERE Moon ='P4';
UPDATE dbo.Moons
SET Moon = 'Styx'
WHERE Moon ='P5';
CreateAndPopulatePlanetMassesTable.sql
USE Solar_System
CREATE TABLE Planet_Masses
(
PID VARCHAR(1)NOT NULL PRIMARY KEY,
Base_kg FLOAT NOT NULL,
Exponent FLOAT NOT NULL,
Gravity_mps2 FLOAT NULL
);
UpdatePlanetMassesTable.sql
/* Execute this query separately before updating the table data.
USE Solar_System
ALTER TABLE dbo.Planet_Masses
ADD Weight_lb INT NULL;
*/
USE Solar_System
UPDATE dbo.Planet_Masses
SET Weight_lb = 38 WHERE PID ='1'
UPDATE dbo.Planet_Masses
SET Weight_lb = 91 WHERE PID ='2'
UPDATE dbo.Planet_Masses
SET Weight_lb = 100 WHERE PID ='3'
UPDATE dbo.Planet_Masses
SET Weight_lb = 38 WHERE PID ='4'
UPDATE dbo.Planet_Masses
SET Weight_lb = 253 WHERE PID ='5'
UPDATE dbo.Planet_Masses
SET Weight_lb = 107 WHERE PID ='6'
UPDATE dbo.Planet_Masses
SET Weight_lb = 91 WHERE PID ='7'
UPDATE dbo.Planet_Masses
SET Weight_lb = 114 WHERE PID ='8'
UPDATE dbo.Planet_Masses
SET Weight_lb = 7 WHERE PID ='9';
CreateProcedure_sp_find_closest.sql
CREATE PROCEDURE sp_find_closest
AS
BEGIN
SELECT
(SELECT Planet
FROM dbo.Planets AS p1
WHERE m1.PID = p1.PID) AS "Name of Planet",
FROM dbo.Moons AS m1
GROUP BY PID;
END
GO
CreateProcedure_sp_planet_categories.sql
CREATE PROCEDURE sp_planet_categories
AS
BEGIN
DECLARE @tableHTML nVarchar(max)
DECLARE @subject nVarchar(max)
SET @subject = 'Planetary Report'
SET @tableHTML =
N'<html><head><title>Query Results</title></head><body>' +
N'<table width="75%" style="color: red; border: 1 solid black; padding: 1; text-align:
center">' +
N'<caption style="font-size: 24pt">Inner Planets</caption>' +
N'<tr><th> Planet </th><th> Diameter(Km) </th><th> Distance(AU) </th>' +
N'<th> Distance(MKm) </th><th> Rotation(days) </th><th> Orbit(years) </th><th> #
Moons </th><th> Density </th>'+
N'</tr>' +
CAST ( ( SELECT td = Planet, '',
td = Diameter_km, '',
td = Distance_AU, '',
td = Distance_Mkm, '',
td = Rotation_days, '',
td = Orbit_years, '',
td = Num_Moons, '',
td = Density_gpcm3, ''
FROM dbo.Planets
WHERE PID <= 4
ORDER BY PID
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
N'</table>' +
SELECT @tableHTML
END
GO
Appendix E: Additional
Resources
Free DBMS Downloads
Microsoft SQL Server 2008 R2 SP2 Express Edition (includes
SQL Server 2008 R2 SP2 Management Studio Express):
http://www.microsoft.com/en-us/download/details.aspx?id=30438
Download pubs database:
http://www.microsoft.com/en-us/download/details.aspx?id=23654
MySQL for Windows:
http://dev.mysql.com/downloads/windows/
Oracle Database 11g Express Edition
http://www.oracle.com/technetwork/database/database-
technologies/express-edition/overview/index.html
IBM’s DB2 Express-C:
http://www-01.ibm.com/software/data/db2/express-
c/download.html