Python SQL Select Syntax with variable in between - python

I have a SQL statement that works in mysql:
SELECT * FROM `ps_message` WHERE `id_order` = 111 ORDER BY id_message asc LIMIT 1
What is wrong with the following statement in Python:
cursor2.execute("SELECT * FROM ps_message WHERE id_order='%s'" % order["id_order"] " ORDER BY id_message asc LIMIT 1")
How should the syntax be in Python to work?

You have a syntax error in string formatting. Should be:
cursor2.execute("SELECT * FROM ps_message WHERE id_order='%s' ORDER BY id_message asc LIMIT 1" % order["id_order"])
Using format() is also preferable over old-style string formatting. Read more about it here.

Pass the order number as a query parameter.
e.g.
cursor2.execute("SELECT * FROM ps_message WHERE id_order=%s ORDER BY id_message asc LIMIT 1", [ order["id_order"] ])
Note that when using query parameters you don't put quotes around the %s.
This approach is recommended to avoid the risk of sql injection attacks.
It should also be more efficient if there are many queries.
https://docs.python.org/2/library/sqlite3.html
http://pymssql.org/en/stable/pymssql_examples.html

Related

Knowing if the result of a SQL request must be a part of another SQL request result

Let's suppose I have the following table :
Id (int, Primary Key) | Value (varchar)
----------------------+----------------
1 | toto
2 | foo
3 | bar
I would like to know if giving two request, the result of the first must be contained in the result of the second without executing them.
Some examples :
# Obvious example
query_1 = "SELECT * FROM example;"
query_2 = "SELECT * FROM example WHERE id = 1;"
is_sub_part_of(query_2, query_1) # True
# An example we can't know before executing the two requests
query_1 = "SELECT * FROM example WHERE id < 2;"
query_2 = "SELECT * FROM example WHERE value = 'toto' or value = 'foo';"
is_sub_part_of(query_2, query_1) # False
# An example we can know before executing the two requests
query_1 = "SELECT * FROM example WHERE id < 2 OR value = 'bar';"
query_2 = "SELECT * FROM example WHERE id < 2 AND value = 'bar';"
is_sub_part_of(query_2, query_1) # True
# An example about columns
query_1 = "SELECT * FROM example;"
query_2 = "SELECT id FROM example;"
is_sub_part_of(query_2, query_1) # True
Do you know if there's a module in Python that is able to do that, or if it's even possible to do ?
Interesting problem. I don't know of any library that will do this for you. My thoughts:
Parse the SQL, see this for example.
Define which filtering operations can be added to a query that can only result in the same or a narrower result set. "AND x" can always be added, I think, without losing the property of being a subset. "OR x" can not. Anything else you can do to the query? For example "SELECT *", vs "SELECT x", vs "SELECT x, y".
Except for that, I can only say it's an interesting idea. You might get some more input on DBA. Is this an idea you're researching or is it related to a real-world problem you are solving, like optimizing a DB query? Maybe your question could be updated with information about this, since this is not a common way to optimize queries (unless you're working on the DB engine itself, I guess).

Python SQL cursor giving different results?

I have the following function in Python:
def get_emo_results(emo, operator):
cursor.execute("SELECT avg(?) FROM [LIWC Post Stats] "
"WHERE goals_scored {0} goals_taken "
"GROUP BY post_number "
"ORDER BY post_number ASC "
"LIMIT ?".format(operator), [emo, posts_limit])
print "SELECT avg({1}) FROM [LIWC Post Stats] "\
"WHERE goals_scored {0} goals_taken "\
"GROUP BY post_number "\
"ORDER BY post_number ASC "\
"LIMIT {2}".format(operator, emo, posts_limit)
return [x[0] for x in cursor.fetchall()]
I call it with get_emo_results('posemo', '>') and get this output to stdout:
SELECT avg(posemo) FROM [LIWC Post Stats] WHERE goals_scored > goals_taken GROUP BY post_number ORDER BY post_number ASC LIMIT 200
However, the function itself returns
[0.0, 0.0, 0.0, 0.0, 0.0, ... 0.0]
I copy and paste that exact expression in stdout to my SQLite process that I have opened, and I get this:
1.8730701754386
2.48962719298246
2.18607456140351
2.15342105263158
2.33107456140351
2.11631578947368
2.37100877192982
1.95228070175439
2.01013157894737
...
3.37183673469388
So not 0 at all. Why does my Python function return something different despite using the same query? What am I doing wrong?
EDIT:
It now works when I get rid of the question marks and format the string directly. Why don't parameterized queries work in this case?
It is being handled differently because you are parametirzing your query. You can't really parameterize a column name like that. It is trying to protect you from SQL injection so it is (I'm simplifying here, but basically) encapsulating any strings in quotes before passing it to the SQL engine.
Essentially, SQLlite is trying to average the string literal 'posemo'
You can keep your limit parameterized, but when it comes to column names you need to have them hardcoded or else put them in the string with something like format.

Python pass arguments in to query error

I have the following code in python. I get this error ->tuple indices must be integers, not str
How can I pass these values into the query? I have other examples where this approach works perfectly, i don't understand why it's failling here.
def request_events_json(uei,interval,conn):
cur = conn.cursor()
events_query ="""select e.nodeid,n.nodelabel,e.ipaddr,count(*) as total,min(e.eventcreatetime),max(e.eventcreatetime),(regexp_matches (e.eventlogmsg,E': %(.*)'))[1] as msglog
from events e, node n where e.eventuei = (%s) and e.eventcreatetime > now() - interval (%s) and n.nodeid=e.nodeid
group by n.nodelabel,e.nodeid,e.ipaddr,msglog
order by e.nodeid, count(*) desc limit 10;"""
try:
print('## Requesting events ##')
cur.execute(events_query,('uei.opennms.org/syslogd/cisco/line','5 min'))
.......
With my version of PostgreSQL the round brackets after interval are forbidden.
Update:
It is the percent-sign in the regexp. Double it.

Python - Psycopg2, how to mix tuples and strings in cur.execute()?

I'm new to Python and Psycopg2... I'am trying to do a query that uses IN sql statement and other WHERE clauses but I'm getting an error like this:
psycopg2.ProgrammingError: argument formats can't be mixed
From what I understand I'm mixing a Python tuple with strings, here is the SELECT statement:
cur2.execute("SELECT hash FROM jobsads_text\
WHERE\
date_inserted::timestamp::date - now()::timestamp::date <= 0\
AND date_inserted::timestamp::date - now()::timestamp::date >= -7\
AND hash NOT IN %s \
AND lower((%s)) LIKE '%(%s)%'\
ORDER BY date_inserted asc;", ((not_in_sql,), search_field, search_string))
I get error in the query above.
This query bellow runs OK:
cur2.execute("SELECT hash FROM jobsads_text\
WHERE\
date_inserted::timestamp::date - now()::timestamp::date <= 0\
AND date_inserted::timestamp::date - now()::timestamp::date >= -7\
AND hash NOT IN %s \
ORDER BY date_inserted asc;", (not_in_sql,))
My question is... How can I mix the tuple not_in_sql with the strings search_field and search_string?
Any clues?
Best Regards,
t = (1, 3)
search_field = 'c'
search_string = '%something%'
print cursor.mogrify("""\
select *
from p
where
c in %%s
and
lower (%s) like %%s
""" % search_field, (t, search_string))
Will output this:
select *
from p
where
c in (1, 3)
and
lower (c) like '%something%'
psycopg2 will not substitute identifiers like column names so you must substitute then before passing the query as the first argument of the method.

Python and MySQLdb

I have the following query that I'm executing using a Python script (by using the MySQLdb module).
conn=MySQLdb.connect (host = "localhost", user = "root",passwd = "<password>",db = "test")
cursor = conn.cursor ()
preamble='set #radius=%s; set #o_lat=%s; set #o_lon=%s; '%(radius,latitude,longitude)
query='SELECT *, (6371*1000 * acos(cos(radians(#o_lat)) * cos(radians(lat)) * cos(radians(lon) - radians(#o_lon)) + sin(radians(#o_lat)) * sin(radians(lat))) as distance FROM poi_table HAVING distance < #radius ORDER BY distance ASC LIMIT 0, 50)'
complete_query=preamble+query
results=cursor.execute (complete_query)
print results
The values of radius, latitude, and longitude are not important, but they are being defined when the script executes. What bothers me is that the snippet of code above returns no results; essentially meaning that the way that the query is being executed is wonky. I executed the SQL query (including the set variables with actual values, and it returned the correct number of results).
If I modify the query to just be a simple SELECT FROM query (SELECT * FROM poi_table) it returns results. What is going on here?
EDIT: Encapsulated Haversine formula calculation within parenthesis
AFAIK you can't run multiple statements using execute().
You can, however, let MySQLdb handle the value substitutions.
Note that there are two arguments being passed to execute().
Also, just running execute() doesn't actually return any results.
You need to use fetchone() or fetchmany() or fetchall().
cursor.execute('''
SELECT *,
6371*1000 * acos(cos(radians(%s)) *
cos(radians(lat)) * cos(radians(lon) - radians(%s)) +
sin(radians(%s)) * sin(radians(lat))) as distance
FROM
poi_table
WHERE distance < %s
ORDER BY distance ASC
LIMIT 0, 50''', (latitude, longitude, latitude, radius,))
results = cursor.fetchall()
print results
Are you sure that the HAVING clause shouldn't be WHERE distance < #radius instead?

Categories