[APSW] SELECT COUNT(*) not succesfull?

Bruno Desthuilliers bdesth.quelquechose at free.quelquepart.fr
Wed Oct 22 12:35:35 EDT 2008


Gilles Ganault a écrit :
> Hello
> 
> I'm trying to use the APSW package to access a SQLite database, but
> can't find how to check if a row exists. I just to read a
> tab-separated file, extract a key/value from each line, run "SELECT
> COUNT(*)" to check whether this tuple exists in the SQLite database,
> and if not, run an INSERT.
> 
> The problem is that "if not row" isn't run:

It is - the problem is that cursor.execute doesn't return what you 
think... Truth is that according to the db-api specification, the return 
value of cursor.execute is not defined (IOW : can be absolutely 
anything). FWIW, sqlite3 returns the cursor object itself and mysqldb 
returns (IIRC) the numbor of rows affected (selected, updated, 
whatever). Now I don't know what apsw is, but it's common for libraries 
to provide their own wrapping of the db-api. Anyway: it doesn't return a 
'row' in any case.



> ==========
> import apsw
> 
> connection=apsw.Connection("test.sqlite")
> cursor=connection.cursor()
> 
> data = {}
> 
> f = open("data.tsv", "r") 
> textlines = f.readlines()
> f.close()

files are their own iterators, so you could just keep the file opened 
and iterate over it - might save you some memory if the file is huge.

> p = re.compile('^(\d+)\t(\d+)$') 
> for line in textlines:
> 	m = p.search(line)
> 	if m:
> 		data[m.group(1)] = m.group(2)

You do understand that if m.group(1) appears more than one time in 
data.tsv, only the last value will be kept, do you ?

> for (key,value) in data.items():

You don't need the parens around key, value here.

> 	sql = "SELECT COUNT(*) FROM mytable WHERE key='%s'" % key
> 	row=cursor.execute(sql)

The recommended way is to pass the arguments to cursor.execute, ie:

   sql = "SELECT COUNT(*) FROM mytable WHERE key=%s" # cf below
   cursor.execute(sql, (key,))

NB : checks that for your implementation of the db-api, the placeholder 
is %s (this is implementation-specific).

This will do all appropriate preparation of the arguments (quoting etc) 
and will protect you from sql injection. Also, you can now extract the 
sql=<statement> from the loop.

Also, you may want to rewrite your query as "SELECT COUNT(key) FROM 
mytable (etc...)", which (depending on the database engine, the schema 
and a couple other considerations) might be a bit faster


> 	#Why not run?
 > 	if not row:

you want:
         row = cursor.fetchone()
         count = row[0]
         if not count:

> 		print "Row doesn't exist : %s" % key
> 		sql = "INSERT INTO mytable (key,value) VALUES ('%s',%u)" %
> key,value

same remark as above.

> 		cursor.execute(sql)
> 
> connection.close(True)
> sys.exit()

If it's the end of your script, this last statement is useless.

HTH



More information about the Python-list mailing list