下面分别说明 Python 导入 Excel 数据时的类型对应,以及从 MySQL 查询数据时的类型对应。
一、Python 导入 Excel 数据的类型对应关系
Excel 中的数据类型并不像数据库那样严格,它通过“单元格格式”来表达数值、文本、日期、布尔等。Python 读取 Excel 时,使用的库不同,映射规则也会不同,常见的有 pandas.read_excel()(背后引擎可以是 openpyxl 或 xlrd)和直接使用 openpyxl。
1. 用 pandas.read_excel() 读取时的类型映射
pandas 会推断整列的数据类型,返回的 DataFrame 的 dtype 是列的通用类型。单个值的实际 Python 类型依赖于此列 dtype。
| Excel 中的内容/格式 | pandas 列类型 (dtype) | 单元格内的 Python 类型 | 备注 |
|---|---|---|---|
| 常规数字、数值 | int64(无缺失/空)float64(有空值或含小数) | int float | 若包含空值,列会提升为 float64,空值显示 NaN |
| 文本 / 字符串 | object文本型数字视作常规数字、数值 空字符串和空白都被读为 NaN | strint或floatfloat | 混合类型列通常也是 object |
日期(如 2024-01-01) | 若 parse_dates=True 或自动识别(当excel中的日期类型为文本时不被识别,为日期时可以自动识别) → datetime64[ns]若包含空值,空值类型为 NaT | pd.Timestamp NaTType, | 本质是 numpy.datetime64 的封装,可当作 datetime 使用 |
日期+时间(如 2024-01-01 14:30) | datetime64[ns] | pd.Timestamp | 同上 |
纯时间(如 14:30:00) | object | datetime.time | 整列不是时间类型,但是内部是 |
布尔值 TRUE/FALSE | bool(无缺失)float64(有缺失) | bool float(缺失值为float类型) | 含有空单元格时可能退化为 float64,值为 float |
| 空白单元格 | 同列数字列 → float64 下的 NaN 同列文本列 → object 下的 NaN (实为 float) | float | 空值统一为缺失值 空字符串也为缺失值 |
| 公式 | 计算结果的值,按值类型对应上表 | 与计算结果类型一致 | 需要 Excel 计算过的值(读取时使用 data_only=True 的引擎参数) |
错误值 (#DIV/0! 等) | object | str (如 '#DIV/0!') | pandas 默认将错误当作文本 |
日期类型读取
日期和时间能不能读取为日期和时间类型,主要还是看excel中数据有没有被标为日期时间,如果被标为文本,则该列以及列中的数据都不会为日期时间类型
混合类型列
pandas会将整个列当作object类型,每个单元格保留其原始 Python 类型(如同时包含int和str)。当单元格格式能跟数据格式保持一致,或者常规(无特定格式),pandas可以识别每个单元格本来的格式。如果整列被设置为文本,那么在混合列中就不能识别除文本外的其他格式
2. 用 openpyxl 直接读取单元格 .value 时的类型映射
这种方式可以获取每个单元格的精确 Python 类型。
| Excel 单元格类型(数字格式) | openpyxl 返回的 Python 类型 | 说明 |
|---|---|---|
| 整数数字 | int | 如 Excel 中的 100 |
| 小数 / 浮点数字 | float | 如 3.14 |
日期格式(如 yyyy-mm-dd) | datetime.datetime | Excel 序列号转换为 datetime(日期部分有效,时间默认 00:00:00) |
| 日期+时间格式 | datetime.datetime | 完整的日期时间 |
纯时间格式(如 hh:mm:ss) | datetime.time | Excel 内部为小数,openpyxl 转为 time |
时长格式(如 [hh]:mm:ss) | datetime.timedelta | 适用于超过 24 小时的时间差 |
| 文本 / 字符串 | str | |
| 布尔值 | bool | True 或 False |
| 空单元格 | None | |
错误 (#N/A, #VALUE! 等) | str(如 '#N/A') | 需注意,不是异常而是字符串 |
| 公式(工作簿未计算) | 公式字符串(如 '=A1+B1') | 若 data_only=True 且缓存了结果,则返回计算结果值 |
小结与注意点
- Excel 没有独立的“日期”或“时间”类型,它们本质是数字(序列号),通过数字格式显示。
openpyxl能根据格式智能转换为datetime/time/timedelta,而pandas默认只自动处理常见的日期时间列,纯时间列可能需要手动pd.to_timedelta或自定义转换。 - 公式:如果 Excel 文件未保存计算结果,
openpyxl只能读到公式字符串,pandas可能无法读取到期望的值。
二、查询 MySQL 数据时 Python 数据类型的对应关系
同样取决于你使用的 Python 库。最常见的是 DB-API 驱动(如 pymysql、mysql-connector-python) 和 pandas.read_sql(),下面以 pymysql 为例展示标准 DB-API 的映射,再补充 pandas 的差异。
1. pymysql(及大多数 MySQL Python 驱动)的类型映射
默认情况下,游标返回的行中的字段已经转换为对应的 Python 对象。
| MySQL 数据类型 | Python 类型 | 备注 |
|---|---|---|
TINYINT, SMALLINT, MEDIUMINT, INT, INTEGER, BIGINT | int | Python 3 的 int 无上限,能容纳 BIGINT |
FLOAT, DOUBLE | float | |
DECIMAL, NUMERIC | decimal.Decimal | 保留精度,适合金融计算 |
BIT | bytes | BIT(1) 返回 b'\x00' 或 b'\x01' |
BOOL, BOOLEAN | int (0 或 1) | 实际上是 TINYINT(1),默认返回 int;可通过 conv 参数转为 bool |
CHAR, VARCHAR, TINYTEXT, TEXT, MEDIUMTEXT, LONGTEXT | str | |
ENUM, SET | str | 返回枚举/集合的字符串值 |
BINARY, VARBINARY, TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB | bytes | 二进制数据 |
DATE | datetime.date | |
DATETIME, TIMESTAMP | datetime.datetime | |
TIME | datetime.timedelta | MySQL 的 TIME 范围较大(-838:59:59 ~ 838:59:59),timedelta 可完整表示 |
YEAR | int | 返回年份整数(如 2024) |
JSON | str | MySQL 返回 JSON 文本,需手动 json.loads() 解析 |
GEOMETRY | bytes | 返回 WKB(Well-Known Binary)格式字节串 |
NULL | None |
一些可调整的地方
- 布尔值:
pymysql默认将TINYINT(1)转为int。若想直接得到bool,可在连接时设置conv=pymysql.converters.conversions或添加自定义转换器。 - TIME 作为字符串:某些驱动或设置下,
TIME会返回str(如'14:30:00'),可检查驱动文档或连接参数(如pymysql的converter_class)。
2. 使用 pandas.read_sql() 时的类型映射
pandas.read_sql() 底层利用 SQLAlchemy 或 DB-API 游标,并将结果构造成 DataFrame。它会再次调整类型以适合数据分析。
| MySQL 类型 | pandas 列类型 (dtype) | 说明 |
|---|---|---|
整数列 (INT, BIGINT 等) | int64(有空值则变为 float64) | pandas 要求整数列不能有 NaN,有缺失值会提升为 float |
FLOAT, DOUBLE | float64 | |
DECIMAL | float64 或 object | 往往被转为 float,可能丢失精度;也可通过 SQLAlchemy 保留为 Decimal(列类型为 object) |
CHAR, VARCHAR, TEXT 等 | object (元素为 str) | |
DATE | object (元素为 datetime.date) 或 datetime64[ns] | 若连接时加了 parse_dates 参数,则转为 datetime64 |
DATETIME, TIMESTAMP | datetime64[ns] | |
TIME | object (元素为 timedelta 或 str) | 取决于驱动返回的类型,pandas 不会自动转为时间类型 |
BOOLEAN / BOOL | int64 或 bool | 若驱动返回 0/1,则是 int;若返回 True/False 则为 bool |
ENUM, SET | object (字符串) | |
JSON | object (字符串) | 需手动解析 JSON |
空值 NULL | NaN 或 None | 取决于列类型,数值列 NaN,对象列可能是 None 或 NaN |
3. 字节类型转换
从数据库读取 BIT 类型数据时,Python 里得到的往往不是直观的 0/1 或 True/False,常见的是 bytes 或字符串。下面根据不同驱动说明如何还原成正常类型。
1. BIT 数据在 Python 驱动中的常见形态
| 数据库驱动 | 读取 BIT(1) 的返回类型 | 示例值 |
|---|---|---|
| pymysql | bytes | b'\x00' 或 b'\x01' |
| mysql-connector-python | bytearray 或 bytes | bytearray(b'\x01') |
| SQLAlchemy (底层用pymysql) | 通常自动转为 int | 1 |
| 某些ODBC/JDBC桥接 | 字符串 '0' / '1' | '1' |
如果是 BIT(n>1),通常返回对应的字节串,里面存储的是二进制表示,比如 b'\x03' 代表 3。
2. 转换方法
情形一:返回 bytes / bytearray
使用 int.from_bytes() 转为整数,再按需转布尔值。
def bit_to_int(raw):
"""将 bytes/bytearray 转为整数"""
if raw is None:
return None
return int.from_bytes(raw, byteorder='big', signed=False)
# 使用示例
val = b'\x01'
int_val = bit_to_int(val) # 1
bool_val = bool(int_val) # True如果确定只有 0 和 1,也可以更直接:
bool_val = (val != b'\x00')情形二:返回字符串 '0' / '1'
直接 int() 或比较即可。
int_val = int(val) # 1
bool_val = val == '1' # True情形三:可能混入十六进制字符串 "0x01"
先用 int(..., 16) 转换。
if isinstance(val, str) and val.startswith('0x'):
int_val = int(val, 16)3. 封装一个通用转换函数
def parse_db_bit(value):
"""将数据库读取的 BIT 值转为 Python 整数"""
if value is None:
return None
if isinstance(value, (bytes, bytearray)):
return int.from_bytes(value, 'big')
if isinstance(value, str):
# 处理类似 '0x01' 的十六进制字符串
if value.startswith('0x') or value.startswith('0X'):
return int(value, 16)
return int(value) # 普通数字字符串
if isinstance(value, int):
return value
raise TypeError(f"Unexpected BIT type: {type(value)}")4. 从源头改进(连接参数设置)
如果不想每次手动转换,可以在创建连接时让驱动自动转换:
pymysql
设置 conv 参数将 BIT 映射为自定义转换器:
import pymysql
from pymysql.constants import FIELD_TYPE
def bit_converter(value):
if value is None:
return None
return int.from_bytes(value, 'big')
conversions = pymysql.converters.conversions.copy()
conversions[FIELD_TYPE.BIT] = bit_converter
conn = pymysql.connect(
host='...',
user='...',
password='...',
db='...',
charset='utf8mb4',
conv=conversions
)这样所有 BIT 字段查询出来就直接是整数。
mysql-connector-python
该驱动有时会返回 bytearray,可以在游标上设置 binary=True 或使用 raw 模式? 更简单的方法还是后处理,或者使用 converter_class 自定义。但通用性不如后处理。
SQLAlchemy
如果你用的是 ORM,通常模型字段定义为 Boolean 或 Integer 即可自动映射,无需额外处理。
5. 注意 NULL 值
数据库的 BIT 字段允许 NULL,Python 里会得到 None,转换时请保留 None。
建议:如果项目里多处都要查 BIT 字段,最好在数据库连接层统一做转换(比如修改 pymysql 的 converter),一劳永逸;如果只是少量查询,用现成的转换函数更简单。
小结与实用建议
- 从 MySQL 拿数据做精确计算:使用
pymysql直接获取Decimal而不要用pandas将其转为 float。 - 处理时间:
pymysql的TIME→timedelta很方便;而pandas读取时通常需要额外的pd.to_timedelta进行转换。 - 布尔值:如果数据库使用
TINYINT(1)表示布尔,记得根据需要转换int→bool。 - JSON 字段:从 MySQL 查出来默认是字符串,一般需要
json.loads()解析成字典或列表。
总的来说,Python 与 Excel 的类型映射高度依赖读取库及其参数,Python 与 MySQL 的映射则由驱动和是否使用 pandas 决定,但大体遵循上述规则。搞清楚这些对应关系,在数据清洗和格式转换时就能避免很多隐式错误。