1

I have a database full of information and I'm trying to write a python script that will pull some of the data and organize it into a report. Here's what I have so far:

import cx_Oracle
import pandas as pd

conn = cx_Oracle.connect('REDACTED')
cursor = conn.cursor()

# Currently hard-coded to return single known motor number
cursor.execute('SELECT MOTORID FROM MOTORS WHERE SERIALNUM=804')
# Returns [(11)]
lMotorID = cursor.fetchall()

# Query Assessments for list of how long the motor had run when assessment was taken
cursor.execute("SELECT DISTINCT RUNHOURS FROM ASSESSMENTS WHERE MOTORID = %s \
               ORDER BY RUNHOURS" % lMotorID[0])
# Returns [(0), (0.91), (8), (25), ...]
lHours = cursor.fetchall()

# Query for number of installed sensors by senor type
cursor.execute("SELECT SENSTYP, COUNT(STATUS) FROM HEALTH LEFT JOIN INSTRUMENTATION \
               ON HEALTH.INSTROID = INSTRUMENTATION.INSTROID LEFT JOIN ASSESSMENTS \
               ON HEALTH.ASSESSID = ASSESSMENTS.ASSESSID WHERE ASSESSMENTS.ASSESSID \
               IN (SELECT ASSESSID FROM ASSESSMENTS WHERE MOTORID = 11 AND RUNHOURS = %s) \
               GROUP BY SENSTYP ORDER BY SENSTYP" % lHours[2])
# Returns a 2-column dataframe with sensor type in column 0 and the total in column 1
dfTotal = pd.DataFrame(cursor.fetchall())

Because I want this to work for any motor, I want to replace the hard-coded MOTORID = 11 with a variable. I tried replacing the last query with this:

cursor.execute("SELECT SENSTYP, COUNT(STATUS) FROM HEALTH LEFT JOIN INSTRUMENTATION \
               ON HEALTH.INSTROID = INSTRUMENTATION.INSTROID LEFT JOIN ASSESSMENTS \
               ON HEALTH.ASSESSID = ASSESSMENTS.ASSESSID WHERE ASSESSMENTS.ASSESSID \
               IN (SELECT ASSESSID FROM ASSESSMENTS WHERE MOTORID = %s AND RUNHOURS = %s) \
               GROUP BY SENSTYP ORDER BY SENSTYP" % (lMotorID[0], lHours[2])) 
dfTotal = pd.DataFrame(cursor.fetchall())

And that's when I get the ORA-00936 error. I don't understand why the query is complete with a hard-coded value, but not when the value is replaced by a variable (one that works in a previous query). Thanks in advance.

4
  • Aside from the point about using bind variables, try printing your variables, or do a try catch and print Cursor.statement to see exactly what query is being run. I suspect your lMotorID[0] is actually NULL. Commented Nov 6, 2019 at 16:01
  • @kfinity Then why does lMotorID[0] work in the 2nd query (Begins # Query Assessments)? Commented Nov 6, 2019 at 17:44
  • Good point, you probably have a different issue. I'd still recommend printing your variables and/or the full query. Commented Nov 6, 2019 at 17:47
  • 1
    Doing a try except finally definitely helped. Adding print(cursor.statement) to the except block showed me that it was passing tuples rather than the values. Adding [0] after each variable got me the actual value and then the query worked. Thanks! Commented Nov 6, 2019 at 17:52

1 Answer 1

2

Need to fix the syntax for cursor.execute such as

cursor.execute('... WHERE MOTORID = :mt_id AND RUNHOURS = :run_hr', mt_id=lMotorID[0][0], run_hr=lHours[2][0])

prefixing the parameters by percentage sign is valid for MySQL connections through python, while Oracle accepts colons.

or another option would be using an ordered tuple :

cursor.execute('... WHERE MOTORID = :1 AND RUNHOURS = :2', (lMotorID[0][0],lHours[2][0]))
Sign up to request clarification or add additional context in comments.

4 Comments

For further reading, see the documentation: cx-oracle.readthedocs.io/en/latest/user_guide/bind.html
True, never format query inline with %, it can lead at least to SQL injection vulnerability
I tried both of these options and both times I got "NotSupportedError: Python value of type tuple not supported."
I tried on python 3.6.5 ad Oracle DB 12.1.0.2, there is no problem with none of the options. Btw, third option might be using brackets to wrap a tuple such as [ lMotorID[0], lHours[2] ] @SMPerron

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.