You are on page 1of 16

Looping exercise –(3)

Basic loop to count events for each year


1. The aim of this exercise is to create a query to show the number of events which
occurred in each year that you have been alive, using a loop to run a separate
select statement for each year:

The first few results for a Wise Owl born in 1981.

See below for details on how to do this.

The main parts of a loop are the starting point, counter, counter increment and end point
- once you have these the rest of the loop is just the tasty filling:

-- create the counter, normally a variable


DECLARE @Counter INT =
-- create an end point to stop the loop
DECLARE @EndValue INT =
-- start the loop and set an end point
WHILE @Counter <=>
BEGIN
--Everything else
SET @Counter = @Counter + 1 --Increase the counter
END

Set the initial value of the counter to your year of birth, and loop until this reaches the
current year (use year(GetDate())). You can then use the counter within your loop to filter a
select statement counting the number of events.

Optionally save this as Going Loopy.sql and close it down.

Looping into list variables


2. Ever wondered which month is the most eventful? Or which month an event
occurred in? Create a loop to list the events in each month, by looping from
month number 1 to 12:
Loops can save you time on repetitive tasks (although they can't save you from all these exercises ...
).

The hardest part in creating this query is changing the month number into the month
name, as sadly there is no in-built function. Here's one way to achieve this:

Optionally save this as Automation is the future.sql, then close it down.

Find first n primes using looping


3. Your task is to write a query to show the first (say) 1000 primes. Here's a
suggested algorithm:

 Create an integer variable to hold the value whose primeness you're testing
 Use WHILE to loop until this integer is 1000, incrementing its value by 1 each
time round the loop (let's call this number P)

Within this outer loop:

 Find out the square root of the number you're testing (use SQRT)
 Find out what the highest integer is just below this (use FLOOR) - let's call this X
 Try dividing each number from 1 up to and including X into P
 If we ever find a number such that P % X = 0 (ie that P leaves a remainder of 0
when divided by X) we have a non-prime, and we should flag this accordingly
and break out of the loop

If it helps, here's what you should see to start with:

The first few primes!


If you get this working, try incorporating a timestamp to see how long it took to run:

The start of the time test - at the end, set @EndTime and use DateDiff(ms, @StartTime, @EndTime)
to work out the difference in milliseconds

Save your hard work as Printing primes.sql, then close it down!

Check the Next Pages for Better Understnding…..


Description Prime numbers are positive integers that can only be divided evenly by 1
or themselves. By definition, negative integers, 0, and 1 are not
considered prime numbers. The list of the first few prime numbers looks
like:

2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, ...

For example, 5 is a prime number because you can divide 5 by 1 evenly


and divide 5 by 5 without a remainder, but if you divide 5 by any other
integer, you get a remainder.

5/1 =5
5/2 = 2 plus a remainder
5/3 = 1 plus a remainder
5/4 = 1 plus a remainder
5/5 =1
5/6 = 0 plus a remainder
... = 0 plus a remainder

Now look at the number 4 which is not a prime.

4/1 = 4
4/2 = 2
4/3 = 1 plus a remainder
4/4 = 1
4/5 = 0 plus a remainder
... = 0 plus a remainder

The number 4 can be divided by 2 evenly, so it is not a prime.

The flowchart shown above describes a function that is given a number i


and returns whether it is prime or not. The name of the function is
"IsThisNumberPrime." First it checks to make sure the input number is
an integer. Then it checks to make sure the input number is not
negative, 0 , or 1. Negative integers, 0, and 1 are not considered prime
by definition.

Next the function tries to divide the input number by i, where i = 2, 3, 4,


5, and so forth, to see if it divides any of them evenly, that is, without a
remainder. If the input number is divided evenly, it is not a prime. The
check stops when i is equal to the input number.

You give the function a number and the output is "Yes" if the number is
prime, or "No" if it is not.

Now suppose you want to calculate the first 100 prime numbers. A
flowchart to show that process is shown below.
The flowchart above starts with the number 2 and checks each number
3, 4, 5, and so forth. Each time it finds a prime it prints the number and
increments a counter. When the counter hits 100, it stops the process.
To determine whether a number is prime, it calls the function
"IsThisNumberPrime" which is shown at the top of this page.

The first few primes are quickly calculated, but as the primes get further
apart the computation time increases. Finding large primes is a task for
super computers.
SQL exercises on TRANSACTIONS –(5)

Add Shaun the Sheep as a new doctor within a transaction


USE Doctor Who training database.

1. Write a query to add Shaun the Sheep as Doctor Who number 13 in


the tblDoctor table, but first begin a transaction:

-- this should go within a transaction


INSERT INTO tblDoctor(
DoctorName,
DoctorNumber
) VALUES (
'Shaun the Sheep',
13
)

Extend this query (without running it yet) so that it:

 Tests to see whether 2 + 2 = 4;


 Rolls back the transaction if this is true; or
 Commits it if this is false.

Use the SQL syntax IF ... ELSE ....

Finally, display a list of all of the doctors (the rows from the tblDoctor table). Now run
your query - it should show the original 12 doctors (Shaun the Sheep has not beeen
added).

Amend your query to test whether 2 + 2 = 5, and rerun it. You should now get your new
doctor:
The transaction has been committed, and the new doctor appears in the list.

Manually delete this added row, then (optionally) save this query as Baad
example.sql and close it down.

Update table, then undo changes with a transaction


2. Use an UPDATE statement on the tblCountry table to set the CountryName column
to include the words (My Country) next to the country you call home:

Just saying....

Now change the code to add (Holiday destination) to the other countries within a
transaction. After running the update statement:

 roll back the transaction if 1 + 1 = 2 (it does); or


 commit it otherwise.

When you run this query, nothing should change:


When excluding your country remember to use wild cards to account for the changed name!

Change the condition to test whether 1 + 1 = 3 (it doesn't), and rerun it. Check that the
extra text has been added:

If you have nothing better to do, change Holiday to Visited for countries you've been to.

Finally, as a bit of housekeeping please reset the country names by running this query:

-- reset country names


UPDATE tblCountry
SET CountryName = REPLACE(CountryName,
' (Holiday Destination)','')
-- check this worked
SELECT * FROM tblCountry

If you could also manually reset the name of your home country back to its former glory, that would
be good! Thanking you ...

Optionally save this as Stake your claims.sql, and then close it down.

Creating transaction with an insert command


3. Write an insert statement to add a new event with EventName called My
DOB , with your date of birth as the Eventdate column and an appropriate
entry for the EventDetails column:

Remember INSERT INTO tblEvent and VALUES.

Now we can turn this insert into a transaction - but first, write a delete command to
remove any events with an Eventname like My DOB.

DELETE FROM tblEvent WHERE EventName LIKE 'My DOB'

Create a transaction which tests if an Eventname of My DOB exists already, adding it if


it doesn't and giving a message if it does:
Results of running the script for the first and second times. Your EventID will be different!

Optionally save this as Adding dates of import.sql then close it down.

Using Insert, Update and Delete in transacitons


4. First store the value of Westeros in a variable. Now write an insert
statement to add the value of this variable into the ContinentName field:

INSERT INTO tblContinent (ContinentID,ContinentName)


VALUES (9,@Continent)

Note that to do this you will first need to get SQL Server to overwrite the ContinentId identity
column by running the command SET IDENTITY_INSERT tblContinent ON. Don't forget to turn
this property off at the end of your query.

After running the Insert statement, comment it out but leave the variable.

You should now see Westeros appearing in the list of continent names when you select them. The
question is: which is the deadliest continent?

Start a TRANSACTION to delete the continent held in the variable, using this syntax:

DELETE tblContinent
WHERE ContinentName = @Continent

If the first letter of your name is not equal to (<>) the first letter of the variable (W) then
roll back the transaction:
In this case, show the message You have died and update the continent name of Westeros to Seven
Kingdoms, then select all the continents.

Set the ELSE condition to show You have won and to then select all the continents.

The outcome now will depend on your name. If it is W then you will see no continent:

You survived and the seven kingdoms of Westeros are gone. Danny would be proud!

For those less fortunate of us, you will have died. Change the <> to an = and rerun the
script. This time you should see Seven Kingdoms and a happier message.

Optionally save this as Game Of Thrones.sql and close it down.

Populate a column, then (maybe) roll back the transaction


USE Doctor Who training database.

5. Type in and run the following script to generate a new column


called NumberEnemies in the tblEpisode table:

ALTER TABLE tblEpisode


ADD NumberEnemies int

Write an update query which will set this column to equal the number of enemies for
each episode (but within a transaction), then:
 Roll back this transaction if more than 100 rows are affected (displaying a
suitable message, as shown below); or
 Commit it otherwise and show a list of all of the episodes, including the newly
populated field.

Use @@RowCount to see how many rows are affected, but don't forget to store this in a variable
immediately after running the update so that its value doesn't get overwritten.

Note that the syntax of the update query is nasty:

-- set the number of enemies for each episode


UPDATE
tblEpisode
SET
NumberEnemies = (
SELECT
COUNT(*)
FROM
tblEpisodeEnemy AS ee
WHERE
ee.EpisodeId = e.EpisodeId
)
FROM
tblEpisode AS e

When you run this query, you should see something like this:

Because 117 rows were updated, your query should roll back the transaction.

Now change the threshold in the query from 100 to 120 and re-run it. This time the
query should update the column, and display the results:
You have to wait until episode id 15 to get more than one enemy (at which point 3 come along at
once).

When you've got this working, optionally save your query as Counting your
enemies.sql, then close it down.

SQL exercises on DYNAMIC SQL-(4)

Basic dynamic SQL to pass in table name


1. The aim of this exercise is to be able to pass different table names to a
select statement, to show different sets of rows. First create a stored
procedure which selects everything from the table tblEvent:

The first few events.

Now add a varchar(max) parameter called @TableName to hold the name of the table
from which you want to extract data, and use its value in place of tblEvent in
the FROM clause. Sadly this doesn't work and results in an error:

It takes a while to accept that this can't work!

Declare a varchar(max) variable called @SQL, and set it equal to the SQL script up to
the FROM keyword, then add your parameter value on the end:

Then finally either use EXEC (@SQL) or Exec SP_SQLEXEC @SQL at the bottom of
the stored procedure to run the select statement contained in your variable.

Now try running the stored procedure:

Try passing in each of the tblEvent, tblCountry and tblContinent table names.

Optionally save this as Turning the table.sql, and close it down.


Use dynamic SQL to create a procedure with varying sort order
USE Doctor Who training database.
2. Create a procedure called spEpisodesSorted which takes two
parameters:

Parameter What it does Default value

@SortColumn The name of the column to sort by EpisodeId

@SortOrder The order to sort by (ASC or DESC) ASC

Declare and build up a string variable called @sql which contains a SELECT command
based on the value of these two parameters, and execute it like this:

-- run command contained in variable


EXEC(@sql)

You should now be able to list the Doctor Who episodes in different orders! For
example:

-- show episodes in default order


spEpisodesSorted
GO
-- show episodes in reverse title order
spEpisodesSorted 'Title', 'DESC'

When you've got this working, optionally save the query as Allsorts.sql, then close it
down.

Dynamic SQL
3. If you haven't already done so, run the stored procedure in the above
folder to generate a database of training courses and attendees.

Create a stored procedure to take in various different parameters about a query:


Your procedure should allow you to vary the columns, table, number of rows selected and sort order

Your stored procedure should build up a string of text containing a SQL command, then
execute it:

The command to execute an SQL command contained in a string variable

You should then be able to run your stored procedure (when you've finished it!) to show
data from different tables in different ways. For example:

Two completely different SELECT statements, using the same stored procedure

If it helps, here's the sort of string of text you should be aim to be building up: SELECT TOP 5
FirstName,LastName FROM tblPerson ORDER BY LastName.

Optionally, save the code to generate your stored procedure as Variable inputs.sql,
then close it down.

Filtering using list variables with Dynamic SQL


4. Create a comma-delimited list variable containing all of the names of
events that occurred in your decade of birth. Use LEFT to remove the
extra comma, and QUOTENAME to add apostrophes.

This owl's generation is between 1980 and 1989, resulting in 72 events.

Now use this list to filter another select statement which shows all of (*) the information
about those events from the event table. You will need to use dynamic SQL:
The top 5 results for the same owl.

Optionally save this as It's a generational thing.sql and close it down.

You might also like