SQL Exam 6
SQL Exam 6
SELECT
*
FROM
dbo.fnEventsForYear(1918) AS e
If you get this working, create another query which joins to the results of your table-
valued function to show the category and country for each event in a given year:
Optionally, save all this as Annual events, then close down your query.
Table function to summarise a continent for month
2. The aim of this exercise is to create a function that returns summary information
about a given continent during a chosen month. For example, you should be
able to run this command:
Passing in Europe and April like this should give the following results:
Create a table-valued function to list out all of the episode details for a given doctor.
Here's the syntax, as a reminder:
You should be able to run this query to show the episodes in which anyone
called Chris appeared:
Create a query based on this (you'll need to give the results returned by the function a
table alias, and create a join from this to the tblAuthor table) to show the details
(including author) for episodes made by doctors called Chris:
The 13 episodes made by Christopher Eccleston, bringing in the author name from
the tblAuthortable.
4. You'll find this exercise much easier to do if you have access to the following
scalar functions:
You may have already created these as part of a (much) earlier exercise on variables; otherwise, this
should be your first task!
Write a function (the one in the answer is called fnSilly, for reasons which will become
apparent) which takes two arguments:
The easiest way to describe what your function should return is by example. If you run
this SQL:
There are 2 episodes featuring Wilf, and 4 featuring the Ood (although one of the episodes is the
same in each case).
The important thing to notice is that where an episode is selected by reason of its companion,
the Appearing column shows a comma-delimited list of the companions appearing in the episode;
where it is selected by reason of its enemy, the Appearing column shows a comma-delimited list of
the enemies appearing in the episode.
Still bored? You could always work out how to combine the companions and enemies
in the Appearing column for a duplicated episode, to avoid it appearing twice in the list
(this isn't included in the answer!).
5. Create a function to list out the episodes for any given series number and part of
an author name. This could begin:
This would show the 9 series one episodes written by Russell T. Davies:
Functions can't have optional parameters, but you can pass dummy values and detect
them. Amend your function so that it shows:
Episodes for any series if you pass the first argument as Null;
Episodes for any author if you pass the second argument as Null.
To help you know whether you've succeeded, here's what 4 possible combinations
should show:
-- there is 1 episode written by Steven Moffat for series 2
SELECT COUNT(*) FROM dbo.fnChosenEpisodes(2,'moffat')
-- -- there are 14 episodes in series 2 (for any author)
SELECT COUNT(*) FROM dbo.fnChosenEpisodes(2,null)
-- there are 32 episodes written by Steven Moffat (for any series)
SELECT COUNT(*) FROM dbo.fnChosenEpisodes(null,'moffat')
-- there are 117 episodes (any series, any author)
SELECT COUNT(*) FROM dbo.fnChosenEpisodes(null,null)
Optionally, save your query as Series and author.sql, then close it down.
The top 4 results when you run your function using the vowel I as input, for example.
The function will need one parameter to take in the vowel and a table variable to store
the output from each separate select.
If you call your function once for each vowel within a SELECT statement, you could
display the results for each vowel:
A shock result - E wasn't the most common vowel.
Only 3 events have the holy grail: both THIS and THAT.
To do this you can find all events whose EventDetails column contains the
word this or that respectively, using the LIKE keyword.
In a single query solution you would have to use a CASE expression to determine the
value of IfThisand IfThat, then group by the same CASE expression. This is messy,
and makes it hard to make subsequent changes to your expression (as you have to do
it in two places). Read on!
Pass What to do
Create a CTE (called ThisAndThat?) to determine the values of the IfThis and IfThat flags
1
for each event.
2 Use this CTE to get the required results, as shown at the start of this exercise.
-- create CTE
WITH CteName AS (
SELECT ...
)
-- then immediately use it
SELECT ... FROM CteName
If you get this working and still have spare time, try changing or extending your query to
show the 3 events whose details contain both this and that:
Other than the text they contain, there's no obvious link between these 3 events.
Optionally, save this query as This and that.sql, then close it down.
Your query should return 300 results (including the CountryID column will allow us to join to
the tblCountry table).
Now turn this select into a derived table called Second_Half_Derived. The layout will
be something like this:
--Outer select
SELECT
EventName
FROM
(
--Your select goes here
) AS Second_half_Derived
Now join tblCountry to the derived table as you would for a normal table:
This should return 230 results - scroll down for some happier events.
3. The aim of this exercise is to use a CTE (Common Table Expression) to extract
data from the database in two passes:
1. Get a list of all of the episodes written by authors with MP in their names.
2. Get a list of the companions featuring in these episodes.
You get no points for pointing out that you could do all of this in a single query!
Start by creating a query to show just the episode id numbers for those Doctor Who
episodes written by authors with MP as part of their names:
This should return 4 episodes (one written by Keith Temple, as it happens, and 3 by Steve
Thompson).
Your final query should join to your CTE to show the companions featuring in these
episodes (you may need to use the word DISTINCT to avoid some companions' names
appearing twice):
The results: 4 companions feature in episodes written by authors whose names contain MP.
Optionally, save your query as If that is not useful.sql, then close it down.
1 Get a list of those events which contain none of the letters in the word OWL 3 rows
Use this to get a list of all of those events which take place in the countries for
2 9 rows
the events in list 1.
Get a third list of all of the events which share the same categories as any of the 116
3
events in the second list. rows
If you display the results in date order, you should get this:
The first few of the 116 events returned by your final query.
In the event that you get this working, save your query as Owl-free events, then close it
down.
Here's what NOT to do - we want to avoid repeating the same calculation twice.
To do this, you can do the calculation in two bites, using a CTE to hold the intermediate
stage. First create a query to show the era for each event:
You could peek at the expression at the start of this exercise to get help on how to calculate the era!
Now store this as a CTE, and write a query using it which shows the number of events
per era:
What the entire query should show when you run it.
Each menu has an id number, and also contains within its record the id of its parent
Use a recursive CTE based on this table to show all of the menus, with breadcrumbs:
This is what the results should look like!
It's worth noting that there are many ways to solve this in SQL, but as is so often the case CTEs seem
to give the most intuitive approach.
You can then join them together to show that there is only one country in both camps.
We won't spoil the surprise, but it has (in the Wise Owl database, at any rate) 4
countries and 9 events.
TopCountries The ids of the 3 countries with the most events (use TOP 3)
TopCategories The ids of the 3 categories with the most events (use TOP 3 again)
Use these to show all possible combinations in a final SELECT statement which should
look like this:
The cross join gives all possible combinations of rows in the two CTEs - see below for what the
results should look like.
If you still have the energy, use this to show the number of events for each
combination:
United Kingdom / Politics is the combination of country and category which has the most events.
9. The aim of this exercise is to show a list of all of the enemies appearing in Doctor
Who episodes featuring Rose Tyler, but not David Tennant.
It's possible - probable, even - that you could do this with a single SELECTstatement, but CTEs
make it so much easier to divide a complicated query into two simpler parts!
First create a query to show the episode id numbers for the 13 episodes which feature
Rose Tyler as a companion, but not David Tennant as the Doctor.
Linking to this as a CTE, show the 8 enemies which appear in these episodes (some
more than once):
The enemies corresponding to episodes featuring Rose Tyler, but not David Tennant.
10. Create a query which lists the David Tennant episodes for which none of the
enemies appear in any non-David Tennant episodes:
The first few of the 31 David Tennant episodes which don't share any enemies with any
other non-Tennant episodes.
There are probably hundreds of ways to do this in SQL, and the answer given doesn't claim
to use a particularly efficient one.
First create a query to list out for each event id the positions (if any) of the
words this and that:
The first few events in the list - the last two columns give the position (if any) at which the
words this and that can be found.
Now using this as a CTE, show the two events which contain both words in the right
order (ie thisfollowed by that). You'll need to join your CTE to the events table, so that
you can pick up on the event name and event date, and display them.
The EventDetails column for these two events contains the words this and that, in this order.
Here's the sort of thing you'd have had to write without a CTE (showing how useful
CTEs are!):
SELECT
e.EventName,e.EventDetails,
CHARINDEX('this',e.EventDetails,1) AS ThisPosition,
CHARINDEX('that',e.EventDetails,1) AS ThatPosition
FROM tblEvent AS e
WHERE
-- must contain both strings ...
CHARINDEX('this',e.EventDetails,1) > 0 and
CHARINDEX('that',e.EventDetails,1) > 0 and
-- ... in the right order
CHARINDEX('this',e.EventDetails,1)
CHARINDEX('that',e.EventDetails,1)
Save your query as This and that revisited, and close it down.
Two CTEs to show space category data
12. Space: the final frontier. But it's also one of the countries in the events database.
The aim of this exercise is to list out all the categories of events which occurred in
the Space country:
You'll then list all of the events which didn't occur in Space, with their country names
and categories:
The first few of the 444 events which didn't happen in the Space country.
You can then show the 8 countries which had non-Space events in the same category
as one of the Space events. Read on!
To start with, write a select statement to return the CategoryName of events which
occur in the country Space only:
Perhaps war should be a CategoryName in Space, since the satellite USA-193 was shot down by a
long-range missile?
Now turn this into a CTE so the list is stored in a table that we can join to later. The
layout looks like this:
With CTE_Name
AS
(
Your select statement goes here
)
-- Additional CTEs don't need a second WITH separate with commas
,CTE_Name
AS
(
)
The second CTE should hold a list of all the countries and their categories excluding
(<>) Space. You can then join the two CTEs together based on the CategoryName to
show the final answer:
The 8 countries in which events occurred in terrestrial (ie non-Space) countries, but where these
events' categories were shared by Spaceevents!
Use DISTINCT to remove duplicate countries (some countries had more than one qualifying event).
Optionally save this as Categories Out Of This World.sql then close it down.
This should return 300 rows - including the CategoryID column will allow us to join this CTE to
the tblCategory table.
Now turn this SELECT statement into a CTE called First_Half_CTE. The layout will be
something like this:
WITH First_Half_CTE
AS
(
--Select goes here
)
Now extend your query to join the tblCategory table to the CTE in the same way as you
would join a normal table:
This should return 300 categories (scroll down to see more cheerful events).