jmorrison
jmorrison

Reputation: 191

Python + Sqlite: Unable to determine cause of incorrect number of bindings supplied error

I'll get right into it - I first created a local db for myself:

import sqlite3

conn = sqlite3.connect("tofire.db") #

cursor = conn.cursor()

# create a table

cursor.execute("""CREATE TABLE incidents
                  (Id INTEGER PRIMARY KEY, prime_street text, cross_street text, dispatch_time text, 
                   incident_number text, incident_type text, alarm_level text, area text, dispatched_units text, date_added text)
               """)

This went without a hitch - the next part is my function, and it uses beautiful soup to scrape a table into a list of lists. I am then attempting to write the information in each sublist to the sqlite database.

# Toronto Fire Calls

import urllib2
import sqlite3
import time
import csv
import threading
from bs4 import BeautifulSoup

# Beautiful Soup imports the URL as html
def getincidents ():

    response = urllib2.urlopen('http://www.toronto.ca/fire/cadinfo/livecad.htm')

    html = response.read()

    # We give the html its own variable.

    soup = BeautifulSoup(html)

    # Find the table we want on the Toronto Fire Page

    table = soup.find("table", class_="info")

    # Find all the <td> tags in the table and assign them to variable.

    cols = table.find_all('td')

    # Find the length of rows, which is the number of <font> tags, and assign it to a variable num_cols.

    num_cols = len(cols)

    # Create an empty list to hold each of the <font> tags as an element

    colslist = []
    totalcols = 0
    # For each <font> in cols, append it to colslist as an element.

    for col in cols:
        colslist.append(col.string)
        totalcols = len(colslist)

    # Now colslist has every td as an element from [0] to totalcols = len(colslist)

    # The First 8 <font> entries are always the table headers i.e. Prime Street, Cross Street, etc.

    headers = colslist[0:8]

    # Prime Street
    # Cross Street
    # Dispatch Time
    # Incident Number
    # Incident Type
    # Alarm Level
    # Area
    # Dispatched Units

    # Get the indexes from 0 to the length of the original list, in steps of list_size, then create a sublist for each.
    # lists = [original_list[i:i+list_size] for i in xrange(0, len(original_list), list_size)]
    list_size = 8
    i = 0
    incidents = [colslist[i:i+list_size] for i in xrange(0, len(colslist), list_size)]

    # Works!

    num_inci = len(incidents) # Get the number of incidents
    added = time.strftime("%Y-%m-%d %H:%M")
    update = 'DB Updated @ ' + added

    # SQL TIME, Connect to our db.
    conn = sqlite3.connect("tofire.db")
    cursor = conn.cursor()
    lid = cursor.lastrowid

    # Now we put each incident into our database.

    for incident in incidents[1:num_inci]:
        incident.append(added)
        to_db = [(i[0:10]) for i in incident]
        import ipdb; ipdb.set_trace()
        cursor.executemany("INSERT INTO incidents (prime_street, cross_street, dispatch_time, incident_number, incident_type, alarm_level, area, dispatched_units, date_added) VALUES (?,?,?,?,?,?,?,?,?)", to_db)
    conn.commit()
    print update
    print "The last Id of the inserted row is %d" % lid
    threading.Timer(300, getincidents).start()

getincidents()

I always end up with error message "Incorrect Number of Bindings Supplied" - and it claims that I'm trying to use 9 in my statement when 10 are supplied. I've tried to narrow down the cause of this, but have had no success.

Upvotes: 1

Views: 1061

Answers (2)

unutbu
unutbu

Reputation: 880269

As Ned Batchelder recently put it, "First Rule of Debugging: When in Doubt, Print More Out." After you append added to incident, incident itself has 9 items in it:

print(incident)
# [u'NORFINCH DR, NY', u'FINCH AVE W / HEPC', u'2012-12-09 17:32:57', u'F12118758', u'Medical - Other', u'0', u'142', u'\r\nP142, \r\n\r\n', '2012-12-09 17:46']

So it looks like all you really need to do is use incident as the second argument to cursor.execute. Or, if you want to get rid of some of that whitespace around items like u'\r\nP142, \r\n\r\n', you could use

    to_db = [i.strip() for i in incident]

for incident in incidents[1:num_inci]:
    incident.append(added)
    to_db = [i.strip() for i in incident]
    import ipdb; ipdb.set_trace()
    cursor.execute(
        """INSERT INTO incidents
           (prime_street, cross_street, dispatch_time, incident_number,
            incident_type, alarm_level, area, dispatched_units, date_added)
           VALUES (?,?,?,?,?,?,?,?,?)""", to_db)
    lid = cursor.lastrowid

Upvotes: 1

Joran Beasley
Joran Beasley

Reputation: 114038

You are supplying 10 elements to an insert statement that you have defined to only take 9 elements

either

to_db = [(i[0:9]) for i in incident]  #or
to_db = [(i[1:10]) for i in incident]

will give you nine elements... which matches the number of ? marks in your insert statement (and the number of fields you are populating) ...

which im assuming is what you want

Upvotes: 0

Related Questions