Basic Exercises

This category deals with the basics of SQL. It covers select and where clauses, case expressions, unions, and a few other odds and ends.

Retrieve everything

Retrieve all information from facilities table.

  1. SELECT * FROM facilities
  1. # By default, when no fields are explicitly passed to select(), all fields
  2. # will be selected.
  3. query = Facility.select()

Retrieve specific columns from a table

Retrieve names of facilities and cost to members.

  1. SELECT name, membercost FROM facilities;
  1. query = Facility.select(Facility.name, Facility.membercost)
  2. # To iterate:
  3. for facility in query:
  4. print(facility.name)

Control which rows are retrieved

Retrieve list of facilities that have a cost to members.

  1. SELECT * FROM facilities WHERE membercost > 0
  1. query = Facility.select().where(Facility.membercost > 0)

Control which rows are retrieved - part 2

Retrieve list of facilities that have a cost to members, and that fee is less than 1/50th of the monthly maintenance cost. Return id, name, cost and monthly-maintenance.

  1. SELECT facid, name, membercost, monthlymaintenance
  2. FROM facilities
  3. WHERE membercost > 0 AND membercost < (monthlymaintenance / 50)
  1. query = (Facility
  2. .select(Facility.facid, Facility.name, Facility.membercost,
  3. Facility.monthlymaintenance)
  4. .where(
  5. (Facility.membercost > 0) &
  6. (Facility.membercost < (Facility.monthlymaintenance / 50))))

Basic string searches

How can you produce a list of all facilities with the word ‘Tennis’ in their name?

  1. SELECT * FROM facilities WHERE name ILIKE '%tennis%';
  1. query = Facility.select().where(Facility.name.contains('tennis'))
  2. # OR use the exponent operator. Note: you must include wildcards here:
  3. query = Facility.select().where(Facility.name ** '%tennis%')

Matching against multiple possible values

How can you retrieve the details of facilities with ID 1 and 5? Try to do it without using the OR operator.

  1. SELECT * FROM facilities WHERE facid IN (1, 5);
  1. query = Facility.select().where(Facility.facid.in_([1, 5]))
  2. # OR:
  3. query = Facility.select().where((Facility.facid == 1) |
  4. (Facility.facid == 5))

Classify results into buckets

How can you produce a list of facilities, with each labelled as ‘cheap’ or ‘expensive’ depending on if their monthly maintenance cost is more than $100? Return the name and monthly maintenance of the facilities in question.

  1. SELECT name,
  2. CASE WHEN monthlymaintenance > 100 THEN 'expensive' ELSE 'cheap' END
  3. FROM facilities;
  1. cost = Case(None, [(Facility.monthlymaintenance > 100, 'expensive')], 'cheap')
  2. query = Facility.select(Facility.name, cost.alias('cost'))

Note

See documentation Case for more examples.

Working with dates

How can you produce a list of members who joined after the start of September 2012? Return the memid, surname, firstname, and joindate of the members in question.

  1. SELECT memid, surname, firstname, joindate FROM members
  2. WHERE joindate >= '2012-09-01';
  1. query = (Member
  2. .select(Member.memid, Member.surname, Member.firstname, Member.joindate)
  3. .where(Member.joindate >= datetime.date(2012, 9, 1)))

Removing duplicates, and ordering results

How can you produce an ordered list of the first 10 surnames in the members table? The list must not contain duplicates.

  1. SELECT DISTINCT surname FROM members ORDER BY surname LIMIT 10;
  1. query = (Member
  2. .select(Member.surname)
  3. .order_by(Member.surname)
  4. .limit(10)
  5. .distinct())

Combining results from multiple queries

You, for some reason, want a combined list of all surnames and all facility names.

  1. SELECT surname FROM members UNION SELECT name FROM facilities;
  1. lhs = Member.select(Member.surname)
  2. rhs = Facility.select(Facility.name)
  3. query = lhs | rhs

Queries can be composed using the following operators:

  • | - UNION
  • + - UNION ALL
  • & - INTERSECT
  • - - EXCEPT

Simple aggregation

You’d like to get the signup date of your last member. How can you retrieve this information?

  1. SELECT MAX(join_date) FROM members;
  1. query = Member.select(fn.MAX(Member.joindate))
  2. # To conveniently obtain a single scalar value, use "scalar()":
  3. # max_join_date = query.scalar()

More aggregation

You’d like to get the first and last name of the last member(s) who signed up - not just the date.

  1. SELECT firstname, surname, joindate FROM members
  2. WHERE joindate = (SELECT MAX(joindate) FROM members);
  1. # Use "alias()" to reference the same table multiple times in a query.
  2. MemberAlias = Member.alias()
  3. subq = MemberAlias.select(fn.MAX(MemberAlias.joindate))
  4. query = (Member
  5. .select(Member.firstname, Member.surname, Member.joindate)
  6. .where(Member.joindate == subq))