[Tutor] CSV -> sqlite tables with foreign keys

eryksun eryksun at gmail.com
Wed Oct 17 11:19:27 CEST 2012


On Tue, Oct 16, 2012 at 11:59 PM, Monte Milanuk <memilanuk at gmail.com> wrote:
>
>         address = list(row)
>         address.append(person)
>         row = tuple(address)

The rows from the csv.reader are already lists. Also, the parameter
list in the 2nd argument only needs to be a sequence (e.g. tuple,
list, string), or it can also be a dict if the statement uses named
placeholders.

> from what I've found on the web, I get the distinct impression
> that converting from a tuple to a list and back is considered
> poor practice at best and generally to be avoided.

To update a record in a tuple you can use slicing and concatenation
(+) as an alternative to creating a temporary list.  A list is more
applicable to homogenous data (e.g. a list of tuples, each a data
record). If you want a container for a record that you can modify more
efficiently, use a dict or a custom object. For the latter, look into
ORMs such as Storm:

https://storm.canonical.com/

> Any suggestions?

I found a Stack Overflow answer that uses a table "view" combined with
an "instead of" trigger to update two tables with one insert.

http://stackoverflow.com/a/11715983/205580

Here's my meager attempt at an adaptation (some names have been
changed to protect the innocent...):

    import csv
    import sqlite3

    con = sqlite3.connect(':memory:')
    cur = con.cursor()

    cur.execute('''create table person (
      id integer primary key autoincrement,
      firstname, midinit, lastname, birthdate)
    ''')

    cur.execute('''create table address (
      id integer primary key autoincrement,
      person_id integer references person not null,
      street, city, state, zipcode)
    ''')

    cur.execute('''create view person_view as
      select
        person.firstname, person.midinit, person.lastname,
        person.birthdate, address.street, address.city,
        address.state, address.zipcode
      from
        person inner join address on person.id = address.person_id
    ''')

    cur.execute('''create trigger person_view_insert
      instead of insert on person_view
      begin
        insert into
          person (firstname, midinit, lastname, birthdate)
          values (new.firstname, new.midinit, new.lastname,
                  new.birthdate);
        insert into
          address (person_id, street, city, state, zipcode)
          values ((select last_insert_rowid()),
                  new.street, new.city, new.state, new.zipcode);
      end
    ''')

    import io
    data = io.BytesIO(b'''\
    John,G.,Smith,1972-11-10,123 Any Place,Somewhere,Missouri,58932
    Jane,L.,Jones,1971-12-20,321 Some Place,Anywhere,Kansas,12345
    ''')

    reader = csv.reader(data)
    for row in reader:
        cur.execute('''insert into
          person_view (firstname, midinit, lastname, birthdate,
                       street, city, state, zipcode)
          values (?,?,?,?,?,?,?,?)''', row)

    # output
    for row in cur.execute('select * from person'):
        print row
    for row in cur.execute('select * from address'):
        print row


person table:

    (1, u'John', u'G.', u'Smith', u'1972-11-10')
    (2, u'Jane', u'L.', u'Jones', u'1971-12-20')

address table:

    (1, 1, u'123 Any Place', u'Somewhere', u'Missouri', u'58932')
    (2, 2, u'321 Some Place', u'Anywhere', u'Kansas', u'12345')


More information about the Tutor mailing list