13

I have a MySQL query like:

SELECT mydate, countryCode, qtySold from sales order mydate, countryCode

This returns tuples of tuples with values like:

((datetime.date(2011, 1, 3), 'PR', Decimal('1')), (datetime.date(2011, 1, 31), 'MX', Decimal('1')))

When I try printing this using a loop, it prints perfectly fine:

2011-1-3, PR, 1
2011-1-31, MX, 1

But when I try to return this value, it returns as

datetime.date(2011, 1, 3), 'PR', Decimal('1')

Is there a way that I can get normal data so that I can pass it to UI for processing? By normal data I mean:

[['2011-1-03', 'PR', 1], ...]
Jihoon Baek
  • 730
  • 7
  • 11
arc
  • 133
  • 1
  • 1
  • 4
  • When I do a DATE_FORMAT(mydate, '%Y-%m-%d') output is [['2011-1-03', 'PR', Decimal('1')],[...]] Then I added CONVERT(qtySold, UNSIGNED) output is [['2011-1-03', 'PR', 1L],[...]] Now that the date problem is solve, is they any solution to qtySold? – arc Sep 20 '11 at 11:05

5 Answers5

32

The default converter, MySQLdb.converters.conversions is a dict with entries like this:

{0: <class 'decimal.Decimal'>,
 1: <type 'int'>,
 2: <type 'int'>,
 3: <type 'long'>,
 4: <type 'float'>,
 5: <type 'float'>,
 7: <function mysql_timestamp_converter at 0x89e4454>,
 8: <type 'long'>,
 9: <type 'int'>,
 10: <function Date_or_None at 0x89e43ac>,
 ...
}

You can change the converter and pass that to the connect method like this:

conv=converters.conversions.copy()
conv[246]=float    # convert decimals to floats
conv[10]=str       # convert dates to strings
connection=MySQLdb.connect(
    host=HOST,user=USER,
    passwd=PASS,db=DB,
    conv=conv
    )

The keys 10 and 246 were found by inspecting MySQLdb.converters.conversions in an interactive Python session and making an educated guess based on the default values.

The converter can also be changed after the connection is made:

connection.converter=conv

By the way, how did you resolve the issue with an SQL query? Please add that as an answer.

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • 1
    +1, that explains why I had `Decimal` instances cropping up downstream :) I'm sure you know, but if anyone else comes across this, the constant definitions themselves can be found in `FIELD_TYPE` using `from MySQLdb.constants import FIELD_TYPE` (the constants indicating the MySQL column type - `FIELD_TYPE.DECIMAL = 0`, `FIELD_TYPE.TIMESTAMP = 7`, etc.). – RocketDonkey Jan 17 '13 at 06:13
  • 2
    And as I just discovered, you may want to use FIELD_TYPE.NEWDECIMAL (246) instead of FIELD_TYPE.DECIMAL (0) – albrnick Sep 09 '13 at 14:43
  • If you are using pymysql this will work for you`conv = pymysql.converters.conversions.copy()` – jmcgrath207 Jan 03 '18 at 19:21
  • Is there a way to adjust the converter to prevent unicode strings? I was given the task to migrate a tool from one system to another and it appears some of the background config isn't consistent. Namely, I'm getting a lot of my column identifiers back as u'column_name' which is breaking my javascript. Is there a one-stop place to code for that conversion? – Eddie Rowe Apr 10 '20 at 14:28
6

If you mean you want str types for your dates and int types for your numbers, look at datetime.date.strftime() and int():

>>> datetime.date(2011, 1, 3).strftime("%Y-%m-%d")
'2011-01-03'

>>> int(Decimal(2))
2

If you want to systematically change what types MySQLdb returns for various column types, see the conv keyword argument for MySQLdb.connect():

http://mysql-python.sourceforge.net/MySQLdb.html#mysqldb

Amber
  • 507,862
  • 82
  • 626
  • 550
  • 1
    Anything that I can do at the query level? That'll be of great help. – arc Sep 20 '11 at 10:11
  • You could add items to the type conversion table via the `conv` argument to `.connect()`: http://mysql-python.sourceforge.net/MySQLdb.html#mysqldb – Amber Sep 20 '11 at 10:15
  • (Also see http://mysql-python.sourceforge.net/MySQLdb-1.2.2/public/MySQLdb.converters-module.html#conversions) – Amber Sep 20 '11 at 10:16
  • I'm doing this for the first time. Could you please convert my query using conv – arc Sep 20 '11 at 11:08
  • 2
    If it's your first time, what better time to actually read the docs and learn how to do it yourself? You don't seem to be stuck - I've given you a very direct pointer at what you need to do, and to pages that explain how to do it. If you have a specific question, ask that, but please don't just ask StackOverflow users to write your code for you. – Amber Sep 20 '11 at 11:16
  • This is not my first time. I'm asking for a little help on conv because I did not find much on implementation. BTW, I resolve the issue just using the MySQL query. – arc Sep 20 '11 at 11:24
4

You can avoid to get a convertion by forcing the specific column to be cast as CHAR in your query string

import MySQLdb
import datetime 
conn = MySQLdb.connect(host= "mysql-server",user="weblogadmin", passwd="admin123",db="weblog_db") 
sqlcursor = conn.cursor() 
sqlcursor.execute("SELECT logrole,logserver,logtype,loglevel,CAST(logdatetime AS CHAR),logdetail,logaction,logread FROM logapp_logtable") 
row = sqlcursor.fetchall() 
for data in row:    
    print(str(data)) 
conn.close()
Cilyan
  • 7,883
  • 1
  • 29
  • 37
selfieblue
  • 41
  • 2
3

MySQLdb is trying to be helpful, giving you the Python versions of your SQL datatypes.

However if for some reason need the strings, you can just stringify everything you get back. So something like [[str(val) for val in row] for row in results] should do it.

Dave
  • 11,499
  • 5
  • 34
  • 46
  • Here at the very bottom, with zero votes, is the thing that worked for me. Other answers were syntactically-incorrect. This one worked, specifically, with this syntax: `retVal["rows"] = [[str(val) for val in row] for row in dbCursor.fetchall()]` – philo vivero Jan 05 '17 at 05:26
  • This is not useful when you need proper types back for things like int and float etc. – cerd Aug 04 '17 at 18:00
1

In case you use pymysql instead of MySQLdb, the answer is similar. First you import the converters and constant types. Copy the general converter used, and change the decimal points to convert as floats.

import pymysql
from pymysql.constants import FIELD_TYPE
from pymysql.converters import conversions

conv = conversions.copy()
conv[FIELD_TYPE.DECIMAL] = float
conv[FIELD_TYPE.NEWDECIMAL] = float

After that, use the conv dict in your connection.

connection = pymysql.connect(host = db_host,     
                                 user = db_user,    
                                 passwd = db_pass,
                                 db = db_db,
                                 charset='utf8mb4',
                                 conv = conv,
                               max_allowed_packet = 33554432,
                                    cursorclass=pymysql.cursors.DictCursor)

Now decimal are being converted to float

Dinidiniz
  • 771
  • 9
  • 15
  • thanks, this was helpful for me. Also, for people looking for list of FIELD_TYPE: https://github.com/PyMySQL/PyMySQL/blob/main/pymysql/constants/FIELD_TYPE.py – Vishnu Kumar Jun 15 '22 at 07:59