470,581 Members | 2,438 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 470,581 developers. It's quick & easy.

SQL Query via python

I'm attempting to pass an SQL query via the console:

$ ./getbd month 05

The arguments get seem to passed correctly (via print statements) and then:

cursor.execute ("""
SELECT name, month, day ,category, city FROM bday
WHERE %s = %s
""",(arg1,arg2))

No results. However, if I hardcode the WHERE argument with a field name:

cursor.execute ("""
SELECT name, month, day ,category, city FROM bday
WHERE month = %s
""",(arg2))

It works.

How can I code the left side of the WHERE clause so I can pass an arbitrary
field name to search on?
Thanks,

Jeff Elkins
Jul 19 '05 #1
6 10663
On Fri, 20 May 2005 23:57:01 -0400, Jeff Elkins
<je********@earthlink.net> declaimed the following in comp.lang.python:

The arguments get seem to passed correctly (via print statements) and then:

cursor.execute ("""
SELECT name, month, day ,category, city FROM bday
WHERE %s = %s
""",(arg1,arg2))
You have to remember that .execute(), using the (template,
(arg...)) format, is designed to apply suitable quoting to the
arguments. It does not parse the SQL to determine if arguments are being
used as identifiers and not data values.

The above sample probably generated:

SELECT name, month, day, category, city from bday
WHERE "month" = 5

note the " around month . Obviously, a string /value/ of "month" will
never match a numeric value of 5.

Basically, in any SQL where you are templating /identifiers/
(field names, table names, etc.), you'll need to do /that/ replacement
with Python's % operator. THEN let .execute() quote/substitute the
remaining /data/ values. As others have mentioned though, you'll need to
pre-validate the identifiers if they are coming from user input, to
ensure that someone didn't give you something that is executable SQL and
damaging to the data.

In your example, something like:

validFields = [ "name", "month", "day", "category", "city"]
if arg1.lower() in validFields:
sql = """select .... where %s = %%s""" % arg1.lower()
c.execute(sql, (arg2,))
else:
print "Invalid selection criteria: '%s'" % arg1
print "not found in: %s" % ", ".join(validFields)

-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Home Page: <http://www.dm.net/~wulfraed/> <
Overflow Page: <http://wlfraed.home.netcom.com/> <

Jul 19 '05 #2
On Saturday 21 May 2005 01:32 pm, Dennis Lee Bieber wrote:
On Fri, 20 May 2005 23:57:01 -0400, Jeff Elkins You have to remember that .execute(), using the (template,
(arg...)) format, is designed to apply suitable quoting to the
arguments. It does not parse the SQL to determine if arguments are being
used as identifiers and not data values.

The above sample probably generated:

SELECT name, month, day, category, city from bday
WHERE "month" = 5


This is getting much clearer. Thanks much.

Jeff
Jul 19 '05 #3
Just as an fyi:

In one weekend I have gone from knowing zip about SQL/Python to implementing
code on my personal server that emails info to family about birthdays and
such. I know I could have installed other *nix programs that would do the
same thing, but so what :)

Thanks so much to the folks on this list who took the trouble to reply. I hope
I can pay it forward in the future.

Jeff Elkins

Jul 19 '05 #4
How about:

cursor.execute("""
SELECT name, month, day ,category, city FROM bday
WHERE %(col_name)s = %%s
""" % dict(col_name=arg1),
(arg2)
)

The "%(col_name)s" will be replaced by normal Python string
substitution, while the "%%s" will be quoted by the db module.

Watch out for SQL injection in arg1, though! Maybe check beforehand that
it is a string containing only word characters...

Jeff Elkins wrote:
I'm attempting to pass an SQL query via the console:

$ ./getbd month 05

The arguments get seem to passed correctly (via print statements) and then:

cursor.execute ("""
SELECT name, month, day ,category, city FROM bday
WHERE %s = %s
""",(arg1,arg2))

No results. However, if I hardcode the WHERE argument with a field name:

cursor.execute ("""
SELECT name, month, day ,category, city FROM bday
WHERE month = %s
""",(arg2))

It works.

How can I code the left side of the WHERE clause so I can pass an arbitrary
field name to search on?
Thanks,

Jeff Elkins

Jul 19 '05 #5
On Mon, May 23, 2005 at 04:12:31PM +0000, Austyn Bontrager wrote:
How about:

cursor.execute("""
SELECT name, month, day ,category, city FROM bday
WHERE %(col_name)s = %%s
""" % dict(col_name=arg1),
(arg2)
)

The "%(col_name)s" will be replaced by normal Python string
substitution, while the "%%s" will be quoted by the db module.

Watch out for SQL injection in arg1, though! Maybe check beforehand that
it is a string containing only word characters...


Maybe what you really need is the ability to search for two fields, or
both fields?

Here's an approach that I usually use:

- Write a search function accepting the parameters you search for.
- If you fill one of the parameters with None (in SQL: NULL), you don't
care for its value
- This way, you can narrow your search as much as you like

Here's a quick test script, using pysqlite2 to demonstrate the approach.
It's also not meant as production code, but at least it only works with
SQL parameter binding.

- SQLite uses :name for named parameters instead of %(name)s.
- locals() is a neat hack to access the local variables as a dictionary

#v+
from pysqlite2 import dbapi2 as sqlite

con = sqlite.connect(":memory:")
cur = con.cursor()
cur.execute("create table test(a, b)")
cur.execute("insert into test(a, b) values (1, 2)")
cur.execute("insert into test(a, b) values (1, 3)")
cur.execute("insert into test(a, b) values (2, 3)")

def search(a, b):
global cur
cur.execute("""
select a, b from test
where (:a is null or a=:a)
and (:b is null or b=:b)
""", locals())
return cur.fetchall()

print search(2, None)
print "-" * 50
print search(None, 3)
print "-" * 50
print search(2, 3)
#v-

-- Gerhard
--
Gerhard Häring - gh@ghaering.de - Python, web & database development

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)

iD8DBQFCkgXkdIO4ozGCH14RArjUAJsHgGZ9vVRFgTxB4ocv9e 3+Jya5ZACePYa6
R6fjarUVA5P99/UUBnqgTdo=
=9SOq
-----END PGP SIGNATURE-----

Jul 19 '05 #6

"Jeff Elkins" <je********@earthlink.net> wrote in message
news:ma*************************************@pytho n.org...
Just as an fyi:

In one weekend I have gone from knowing zip about SQL/Python to implementing code on my personal server that emails info to family about birthdays and
such.


Actually - http://www.pythonweb.org/ will handle the SQL (and many other
tasks) in a much simpler way!

If you do try the web.database.object examples, be aware that the docs are
not entirely tracking the code; f.ex. databases have no "type" parameter;
it's an "adapter"

i.e.
connection = web.database.connect(type="sqlite",database="objec t-simple.db")
should be:
connection =
web.database.connect(adapter="sqlite",database="ob ject-simple.db")'

there are probably others - it's good to see what the parameters are in
"idle" if something does not work as advertised.

Overall, Pythonweb is very impressive work IMO.


Jul 19 '05 #7

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

1 post views Thread by Sheila King | last post: by
4 posts views Thread by David Bear | last post: by
17 posts views Thread by erikcw | last post: by
1 post views Thread by livre | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.