This worksheet focuses on SQLite databases. (Last week we also had one lecture about HTML, and we'll come back to that in the next worksheet.)
These things might be helpful while working on the problems. Remember that for worksheets, we don't strictly limit what resources you can consult, so these are only suggestions.
The main references for these topics are:
If possible. But if you can't, you can work on this at the start of lab.
There's nothing to install if you just want to use SQLite with Python, as the module sqlite3
is already part of the Python standard library.
However, if you just want to run one SQL query and show the results, a fairly long Python program is needed, and the results are not presented in a convenient form for experimentation (column headings etc.).
It's much easier if you can install the SQLite REPL (or "command line shell") that lets you run queries directly from a prompt in your terminal, so we strongly recommend installing the command line shell. The instructions in the rest of this worksheet assume you have the command line shell, and you'll need to translate them into corresponding Python programs if you want to avoid installing it.
Lectures 28 and 29 discussed how to install the command line shell. For MacOS and Linux, there's usually nothing you need to do. Here is a quick video showing the steps to install it under windows 10. Other recent Windows versions will be similar.
Here are more detailed written installation instructions by platform.
If you use Windows, you need to install it yourself. The installation doesn't look like the graphical ones you may be used to, with a window and buttons guiding you through the steps. Instead you download a zip file and extract it. The whole thing is relatively quick, but the steps below are described in some detail, so the written instructions are a bit long. (Consider just watching the 1-minute video and following along instead.)
sqlite-tools-win32-x86-
. The description next to the link should begin: A bundle of command-line tools for managing SQLite database filessqlite-tools-win32-x86-3380200
. Double click to enter that folder.You should now see a list of three files, named
sqldiff.exe
sqlite3.exe
sqlite3_analyzer.exe
However, the .exe
may be missing if explorer is configured to hide file extensions (the default).
sqlite3.exe
is the only one you want. Drag that file to the desktop to extract a copy of it.sqlite3
icon on the desktop. Don't click it; we'll work in the terminal instead.cd Desktop
or cd C:\Users\myusername\Desktop
or cd C:\Users\myusername\OneDrive\Desktop
, depding on where PowerShell opens and whether you use OneDrive desktop backup).\sqlite3.exe
.exit
to return to PowerShellsqlite3.exe
file, e.g. C:\Users\myusername\Desktop\sqlite3.exe
.& 'C:\Users\My Username Has Spaces\Desktop\sqlite3.exe'
If you use Linux or MacOS, SQLite's command line shell is almost always pre-installed. Type sqlite3
in a terminal and press enter. Success (meaning it is already installed) looks something like this:
sqlite3
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite>
(at which point you'd want to exit using command .exit
)
Failure (meaning it is not already installed) looks something like this:
$ sqlite3
sqlite3: command not found
If you use Linux or MacOS and SQLite's command line shell is not already installed, contact your TA or instructor for help.
Any time you have your terminal open, there are three situations you may find yourself in:
PS C:\Users\ddumas\Desktop>
or
$
The Python REPL is running, and waiting for a Python statement from you. If this is the case, you'll see a prompt
>>>
and you can quit back to the terminal using the command exit()
.
The SQLite command line shell is running, and is waiting for a SQL command from you. If this is the case, you'll see a prompt
sqlite>
and you can quit back to the terminal using the command .exit
To summarize
When running | prompt looks like | exit with | and then |
---|---|---|---|
Terminal (Windows) | PS C:\Users> |
exit |
window closes |
Terminal (Mac/Linux) | $ |
exit |
window closes |
Python | >>> |
exit() |
back to terminal |
SQLite | sqlite> |
.exit or .quit |
back to terminal |
So you'll need to download this and put the file in a place where you can find it.
The only table in this database is called powerplants
, and the columns present in that table are described at
To confirm you can open the database:
powerplants.sqlite
powerplants.sqlite
as the first command line argument, e.g. a typical Windows command for PowerShell would be
C:\Users\myusername\Desktop\sqlite3.exe powerplants.sqlite
and a typical Linux or MacOS terminal command would be
sqlite3 powerplants.sqlite
After pressing enter, you should see that SQLite is running and waiting for a command with the prompt
sqlite>
.tables
If everything is working, the output should look like this:
sqlite> .tables
powerplants
sqlite>
If you instead see this:
sqlite> .tables
sqlite>
then it means you ran sqlite3
successfully, but in a directory that didn't contain the star database. That directory will now contain an empty file named powerplants.sqlite
, which you should probably find and remove to prevent yourself from later confusing it with the actual database file.I recommend working on these in the SQLite command line shell. Remember, the commands
.headers on
.mode column
will tell SQLite to present output in a more readable format.
Use SQL queries run against the power plant database to answer these questions. (You should consider both the query and its return value as part of the answer.)
For each country below, what is the name, primary fuel, and generation capacity (in MW) of the largest power plant in the database?
Find the northernmost nuclear power plant in the database. What country is it in? What is its location (in latitude, longitude)? What is its generation capacity?
What countries contain wind power plants listed in this database that are located within 5 degrees longitude on either side of the prime meridian?
And among these, which ones contain large wind plants, if we define that as 200MW or greater?
There are columns in the database for net energy output in each of the years 2014 to 2019. But in many cases this information is not available.
What fraction of the power plants listed in the database have output information for 2017?
What fraction of the power plants listed in the database have output information for all of the years 2014 to 2019?
There is a new SQLite feature (or more precisely, a feature of the SQL dialect that SQLite uses for queries) that you'll need to use in this problem.
In many places where we've used column names in our queries, you can also use expressions that apply arithmetic operators and other functions to the values in the columns. For example, if a database of MCS 275 grades has columns called project3pct
and project4pct
, then this query would return the email addresses of students whose grades on those two projects differed by more than 10 percent:
SELECT email FROM mcs275roster WHERE ABS(project3pct - project4pct) > 10;
You can also use expressions like this in the requested list of output columns. For example, this query would get the average of project 3 and 4 percentages for all students, listed in alphabetical order by last name.
SELECT lastname, firstname, 0.5*(project3pct + project4pct) FROM mcs275roster ORDER BY lastname;
Such expressions can also be used after ORDER BY
to make a custom sort.
You can find lists of built-in functions in SQLite in the documentation:
Write a program that stores, delivers, and ranks programming jokes using a SQLite database. It should support three operations:
The program should create the database and table it needs if they don't already exist. Otherwise, it should open and use the existing database.
The three functions should be selected using command line arguments. The first command line argument is always the command---one of add
, tell
, or best
. If the command is add
, then a second command line argument is required, which is the joke itself. If the command is tell
, no other arguments are required but the user is prompted for their approval/disapproval of the joke through keyboard input.
Hints:
INTEGER PRIMARY KEY
so you have a way to uniquely refer to rows.RANDOM()
that will return a random number for each row, and you can order by that. Ordering by RANDOM()
and limiting the number of rows to 1 is equivalent to making a random choice.A
and B
both have type integer then A/B
computes the integer division of A
by B
. In contrast, 1.0*A/B
would give the true quotient because the multiplication by 1.0 converts A
to a float (or REAL
, in SQLite terminology).Save the program as jokedb.py
.
Here is a sample session of what using it should look like. (These are from a linux terminal session, where the terminal prompt is "$". In Windows PowerShell, the prompt will look a bit different.)
$ python3 jokedb.py tell
ERROR: No jokes in database.
[... now suppose several jokes are added ...]
$ python3 jokedb.py tell
There are 10 types of people in the world: Those who understand binary, and those who don't.
Were you amused by this? (Y/N)y
$ python3 jokedb.py tell
The two hardest things in programming are naming things, cache invalidation, and off-by-one errors.
Were you amused by this? (Y/N)n
$ python3 jokedb.py add "Most people agree that there were no widely-used high-level programming languages before FORTRAN. Unfortunately, there is no agreement on whether this makes FORTRAN the 1st such language, or the 0th."
$ python3 jokedb.py tell
Python developers rarely decorate the walls of their offices. They consider whitespace to be significant.
Were you amused by this? (Y/N)y
$ python3 jokedb.py best
-------------------------------------------------------
#1 with 100% success rate after 8 tellings:
Knock knock.
Race condition.
Who's there?
-------------------------------------------------------
#2 with 71% success rate after 7 tellings:
There are 10 types of people in the world: Those who understand binary, and those who don't.
-------------------------------------------------------
#3 with 67% success rate after 6 tellings:
A software testing engineer walks into a bar and orders a refrigerator, -1 glasses of water, and INT_MAX+1 cans of soda.
-------------------------------------------------------
#4 with 60% success rate after 5 tellings:
Python developers rarely decorate the walls of their offices. They consider whitespace to be significant.
-------------------------------------------------------
#5 with 50% success rate after 4 tellings:
The two hardest things in programming are naming things, cache invalidation, and off-by-one errors.
$
Work on this if you complete the problems above.
Here's a scatter plot of all the powerplants in the database that can produce at least 200MW, and the matplotlib code that created it.
import os
os.chdir("/home/ddumas/teaching/mcs275/public/samplecode/sql")
import matplotlib.pyplot as plt
import numpy as np
import sqlite3
con = sqlite3.connect("powerplants.sqlite")
res = con.execute("""
SELECT latitude,longitude
FROM powerplants
WHERE capacity_mw > 200;
""")
longitudes = []
latitudes = []
for row in res:
latitudes.append(row[0])
longitudes.append(row[1])
# Optional: Convert to arrays, which would make it easier
# to do arithmetic or transformations on them.
longitudes = np.array(longitudes)
latitudes = np.array(latitudes)
# Make the plot
plt.figure(figsize=(8,4),dpi=120)
plt.scatter(longitudes,latitudes,s=0.5)
plt.xlabel("longitude")
plt.ylabel("latitude")
plt.show()
Refine this to plot as follows:
(For a real geographic visualization, you'd want to do more---such as adding a legend describing which colors correspond to which types, the outlines of the continents, etc.---but this is a start!)