Modifying Data

Querying data is all well and good, but at some point you’re probably going towant to put data into your database! This section deals with inserting,updating, and deleting information. Operations that alter your data like thisare collectively known as Data Manipulation Language, or DML.

In previous sections, we returned to you the results of the query you’veperformed. Since modifications like the ones we’re making in this section don’treturn any query results, we instead show you the updated content of the tableyou’re supposed to be working on.

Insert some data into a table

The club is adding a new facility - a spa. We need to add it into thefacilities table. Use the following values: facid: 9, Name: ‘Spa’,membercost: 20, guestcost: 30, initialoutlay: 100000, monthlymaintenance: 800

  1. INSERT INTO "facilities" ("facid", "name", "membercost", "guestcost",
  2. "initialoutlay", "monthlymaintenance") VALUES (9, 'Spa', 20, 30, 100000, 800)
  1. res = Facility.insert({
  2. Facility.facid: 9,
  3. Facility.name: 'Spa',
  4. Facility.membercost: 20,
  5. Facility.guestcost: 30,
  6. Facility.initialoutlay: 100000,
  7. Facility.monthlymaintenance: 800}).execute()
  8.  
  9. # OR:
  10. res = (Facility
  11. .insert(facid=9, name='Spa', membercost=20, guestcost=30,
  12. initialoutlay=100000, monthlymaintenance=800)
  13. .execute())

Insert multiple rows of data into a table

In the previous exercise, you learned how to add a facility. Now you’re goingto add multiple facilities in one command. Use the following values:

facid: 9, Name: ‘Spa’, membercost: 20, guestcost: 30, initialoutlay: 100000,monthlymaintenance: 800.

facid: 10, Name: ‘Squash Court 2’, membercost: 3.5, guestcost: 17.5,initialoutlay: 5000, monthlymaintenance: 80.

  1. -- see above --
  1. data = [
  2. {'facid': 9, 'name': 'Spa', 'membercost': 20, 'guestcost': 30,
  3. 'initialoutlay': 100000, 'monthlymaintenance': 800},
  4. {'facid': 10, 'name': 'Squash Court 2', 'membercost': 3.5,
  5. 'guestcost': 17.5, 'initialoutlay': 5000, 'monthlymaintenance': 80}]
  6. res = Facility.insert_many(data).execute()

Insert calculated data into a table

Let’s try adding the spa to the facilities table again. This time, though, wewant to automatically generate the value for the next facid, rather thanspecifying it as a constant. Use the following values for everything else:Name: ‘Spa’, membercost: 20, guestcost: 30, initialoutlay: 100000,monthlymaintenance: 800.

  1. INSERT INTO "facilities" ("facid", "name", "membercost", "guestcost",
  2. "initialoutlay", "monthlymaintenance")
  3. SELECT (SELECT (MAX("facid") + 1) FROM "facilities") AS _,
  4. 'Spa', 20, 30, 100000, 800;
  1. maxq = Facility.select(fn.MAX(Facility.facid) + 1)
  2. subq = Select(columns=(maxq, 'Spa', 20, 30, 100000, 800))
  3. res = Facility.insert_from(subq, Facility._meta.sorted_fields).execute()

Update some existing data

We made a mistake when entering the data for the second tennis court. Theinitial outlay was 10000 rather than 8000: you need to alter the data to fixthe error.

  1. UPDATE facilities SET initialoutlay = 10000 WHERE name = 'Tennis Court 2';
  1. res = (Facility
  2. .update({Facility.initialoutlay: 10000})
  3. .where(Facility.name == 'Tennis Court 2')
  4. .execute())
  5.  
  6. # OR:
  7. res = (Facility
  8. .update(initialoutlay=10000)
  9. .where(Facility.name == 'Tennis Court 2')
  10. .execute())

Update multiple rows and columns at the same time

We want to increase the price of the tennis courts for both members andguests. Update the costs to be 6 for members, and 30 for guests.

  1. UPDATE facilities SET membercost=6, guestcost=30 WHERE name ILIKE 'Tennis%';
  1. nrows = (Facility
  2. .update(membercost=6, guestcost=30)
  3. .where(Facility.name.startswith('Tennis'))
  4. .execute())

Update a row based on the contents of another row

We want to alter the price of the second tennis court so that it costs 10%more than the first one. Try to do this without using constant values for theprices, so that we can reuse the statement if we want to.

  1. UPDATE facilities SET
  2. membercost = (SELECT membercost * 1.1 FROM facilities WHERE facid = 0),
  3. guestcost = (SELECT guestcost * 1.1 FROM facilities WHERE facid = 0)
  4. WHERE facid = 1;
  5.  
  6. -- OR --
  7. WITH new_prices (nmc, ngc) AS (
  8. SELECT membercost * 1.1, guestcost * 1.1
  9. FROM facilities WHERE name = 'Tennis Court 1')
  10. UPDATE facilities
  11. SET membercost = new_prices.nmc, guestcost = new_prices.ngc
  12. FROM new_prices
  13. WHERE name = 'Tennis Court 2'
  1. sq1 = Facility.select(Facility.membercost * 1.1).where(Facility.facid == 0)
  2. sq2 = Facility.select(Facility.guestcost * 1.1).where(Facility.facid == 0)
  3.  
  4. res = (Facility
  5. .update(membercost=sq1, guestcost=sq2)
  6. .where(Facility.facid == 1)
  7. .execute())
  8.  
  9. # OR:
  10. cte = (Facility
  11. .select(Facility.membercost * 1.1, Facility.guestcost * 1.1)
  12. .where(Facility.name == 'Tennis Court 1')
  13. .cte('new_prices', columns=('nmc', 'ngc')))
  14. res = (Facility
  15. .update(membercost=SQL('new_prices.nmc'), guestcost=SQL('new_prices.ngc'))
  16. .with_cte(cte)
  17. .from_(cte)
  18. .where(Facility.name == 'Tennis Court 2')
  19. .execute())

Delete all bookings

As part of a clearout of our database, we want to delete all bookings fromthe bookings table.

  1. DELETE FROM bookings;
  1. nrows = Booking.delete().execute()

Delete a member from the cd.members table

We want to remove member 37, who has never made a booking, from our database.

  1. DELETE FROM members WHERE memid = 37;
  1. nrows = Member.delete().where(Member.memid == 37).execute()

Delete based on a subquery

How can we make that more general, to delete all members who have never madea booking?

  1. DELETE FROM members WHERE NOT EXISTS (
  2. SELECT * FROM bookings WHERE bookings.memid = members.memid);
  1. subq = Booking.select().where(Booking.member == Member.memid)
  2. nrows = Member.delete().where(~fn.EXISTS(subq)).execute()