get raw decimal value from mysqldb query - python

I am executing a mysql query in python using the MySQLdb package. The code looks something like this:
c=db.cursor()
c.execute("""select * from table""")
output = []
for row in c:
output.append(row[4])
where row[4] contains a decimal value that I want to store in the output list.
The problem is every value that I am getting looks like this: Decimal('XX.XX') where all I want in the output list is XX.XX. At the end of the script, my output list looks like this:
[Decimal('10.02'), Decimal('20.24'), ...]
But I need it to just contain the numbers, like this:
[10.02, 20.24, ...]
How do I do that?
Thanks!

You can either convert a Decimal object to a string:
cursor = db.cursor()
cursor.execute("""select * from table""")
output = []
for row in cursor:
output.append(str(row[4]))
Or to a float:
cursor = db.cursor()
cursor.execute("""select * from table""")
output = []
for row in cursor:
output.append(float(row[4]))
Converting it to a float will cause it to lose its full precision, so a value like 20.24 will become 20.239999999999998.
Also, casting it to a float will raise an Exception if the value is None. To avoid that, you can use a helper function like this:
def convert_mysql_decimal_to_float(decimal_object):
if (decimal_object == None):
return None
else:
return float(decimal_object)
cell_value = convert_mysql_decimal_to_float(row[4])

If you are trying to write a generic code that operates on the column output, the above solution won't workout. In that case we can write our SELECT query in a way that the column in returned as String and we just get the value of what we want.
The query can be framed in below way,
SELECT
CAST(COL1 AS CHAR) AS COL1,
CAST(COL2 AS CHAR) AS COL2,
.
.
.
FROM TABLE;

Use float():
output.append(float(row[4]))
But float() can result in something like:
In [184]: float(Decimal('10.02'))
Out[184]: 10.02
In [185]: float(Decimal('20.24'))
Out[185]: 20.239999999999998

To avoid losing precision, you can use Python's decimal module.
from decimal import Decimal
c=db.cursor()
c.execute("""select * from table""")
output = []
for row in c:
row_data = []
for data in row:
if type(data) is Decimal:
row_data.append(float(data))
else:
row_data.append(str(dat))
output.append(row_data)

Related

Converting PYODBC output into an int

Pulling data from a SQL query that gives me 1 number that is stored in a PYODBC row. I want to then add that number to another variable in the file. Pseudocode below -
prev = 5
cursor.execute("select statement")
pulledNumber = cursor.fetchall()
value = [row[2] for row in pulledNumber]
final = prev + value
Getting a type error (list and int operation). Tried to cast the list to an int a few different ways but could not get it to work

Parameterized Python SQLite3 query is returning the first parameter

I'm trying to make a query to a SQLite database from a python script. However, whenever I use parameterization it just returns the first parameter, which is column2. The desired result is for it to return the value held in column2 on the row where column1 is equal to row1.
conn = sqlite3.connect('path/to/database')
c = conn.cursor()
c.execute('SELECT ? from table WHERE column1 = ? ;', ("column2","row1"))
result = c.fetchone()[0]
print(result)
It prints
>>column2
Whenever I run this using concatenated strings, it works fine.
conn = sqlite3.connect('path/to/database')
c = conn.cursor()
c.execute('SELECT ' + column2 + ' from table WHERE column1 = ' + row1 + ';')
result = c.fetchone()[0]
print(result)
And it prints:
>>desired data
Any idea why this is happening?
This behaves as designed.
The mechanism that parameterized queries provide is meant to pass literal values to the query, not meta information such as column names.
One thing to keep in mind is that the database must be able to parse the parameterized query string without having the parameter at hand: obviously, a column name cannot be used as parameter under such assumption.
For your use case, the only possible solution is to concatenate the column name into the query string, as shown in your second example. If the parameter comes from outside your code, be sure to properly validate it before that (for example, by checking it against a fixed list of values).

How to store and query hex values in mysqldb

I want to use a thermal printer with raspberry pi. I want to receive the printer vendor id and product id from mysql database. My columns are of type varchar.
My code is
import MySQLdb
from escpos.printer import Usb
db= MySQLdb.connect(host=HOST, port=PORT,user=USER, passwd=PASSWORD, db=database)
cursor = db.cursor()
sql = ("select * from printerdetails")
cursor.execute(sql)
result = cursor.fetchall()
db.close()
for row in result:
printer_vendor_id = row[2]
printer_product_id = row[3]
input_end_point = row[4]
output_end_point = row[5]
print printer_vendor_id,printer_product_id,input_end_point,output_end_point
Printer = Usb(printer_vendor_id,printer_product_id,0,input_end_point,output_end_point)
Printer.text("Hello World")
Printer.cut()
but it doesnot work. the id's are string. print command shows 0x154f 0x0517 0x82 0x02.in my case
Printer = Usb(0x154f,0x0517,0,0x82,0x02)
works fine.How could I store the same id's to the database and use them to configure the printer
Your problem is that your call to Usb is expecting integers, which works if you call it like this
Printer = Usb(0x154f,0x0517,0,0x82,0x02)
but your database call is returning tuples of hexadecimal values stored as strings. So you need to convert those strings to integers, like this:
for row in result:
printer_vendor_id = int(row[2],16)
printer_product_id = int(row[3],16)
input_end_point = int(row[4],16)
output_end_point = int(row[5],16)
Now if you do
print printer_vendor_id,printer_product_id,input_end_point,output_end_point
you will get
(5455, 1303, 130, 2)
which might look wrong, but isn't, which you can check by asking for the integers to be shown in hex format:
print ','.join('0x{0:04x}'.format(i) for i in (printer_vendor_id,printer_product_id,input_end_point,output_end_point))
0x154f,0x0517,0x0082,0x0002
I should point out that this only works because your database table contains only one row. for row in result loops through all of the rows in your table, but there happens to be only one, which is okay. If there were more, your code would always get the last row of the table, because it doesn't check the identifier of the row and so will repeatedly assign values to the same variables until it runs out of data.
The way to fix that is to put a where clause in your SQL select statement. Something like
"select * from printerdetails where id = '{0}'".format(printer_id)
Now, because I don't know what your database table looks like, the column name id is almost certainly wrong. And very likely the datatype also: it might very well not be a string.

Variable in list name

I have this code :
cur.execute("SELECT * FROM foo WHERE date=?",(date,))
for row in cur:
list_foo.append(row[2])
cur.execute("SELECT * FROM bar WHERE date=?",(date,))
for row in cur:
list_bar.append(row[2])
It works fine, but I’d like to automize this. I have made a list of the tables in my sqlite database, and I’d like something like this :
table_list = ['foo','bar']
for t in table_list:
cur.execute("SELECT * FROM "+t+" WHERE date=?",(date,))
for row in cur:
# and here I’d like to append to the list which name depends of t (list_foo, then list_bar, etc.)
But I don’t know how to do that. Any idea ?
Use a dictionary to collect your data. Don't try to set new local names for each list.
You could use string templating too, and a list comprehension to turn your result rows into lists:
data = {}
for t in table_list:
cur.execute("SELECT * FROM {} WHERE date=?".format(t), (date,))
data[t] = [row[2] for row in cur]
One caveat: only do this with a pre-defined list of table names; don't ever interpolate untrusted input like that without hefty escaping to prevent SQL injection attacks.

Replacing value in all cursor rows

Using SQLite and Python 3.1, I want to display currency data in a HTML table via. a template which accepts a cursor as a parameter. Hence all currency values must have 2 decimal places, but SQLite stores them as float type (even though the structure states decimal :-( ) so some must be converted before display (eg. I want 12.1 displayed as 12.10).
The code goes something like this (simplified for illustration)...
import sqlite3
con = sqlite3.connect("mydb")
con.row_factory = sqlite3.Row
cur = con.cursor()
cur.execute("select order_no, amount from orders where cust_id=123")
for row in cur:
row['amount'] = format(row['amount'],'%.2f')
The last command throws the error "# builtins.TypeError: 'sqlite3.Row' object does not support item assignment"
How can I solve the problem whereby the row object values cannot be changed? Could I convert the cursor to a list of dictionaries (one for each row, eg. [{'order_no':1, 'amount':12.1}, {'order_no':2, 'amount':6.32}, ...]), then format the 'amount' value for each item? If so, how can I do this?
Are there any better solutions for achieving my goal? Any help would be appreciated.
TIA,
Alan
Yep:
cur.execute("select order_no, amount from orders where cust_id=123")
dictrows = [dict(row) for row in cur]
for r in dictrows:
r['amount'] = format(r['amount'],'%.2f')
There are other ways, but this one seems the simplest and most direct one.
An alternative is to store your value as an integer number of cents (which is always an exact amount, no rounding), and then convert to dollars when displaying for reports using divmod:
>>> value_in_cents = 133
>>> print "$%d.%d" % divmod(value_in_cents,100)
$1.33

Categories