如何在Python中对比Parquet文件与数据库Schema(含Decimal精度)
如何在Python中对比Parquet Decimal列与数据库Schema
完全可以以Decimal类型读取Parquet文件并对比精度和刻度,不用转成double(转double会丢失精度,反而影响对比)。下面是具体实现步骤:
1. 读取Parquet文件并保留Decimal原始类型
PyArrow可以直接读取Parquet中的Decimal元数据,不需要自动转成double。通过读取文件的schema就能直接获取列的精度和刻度:
import pyarrow as pa import pyarrow.parquet as pq # 读取Parquet文件,保留原始类型 parquet_table = pq.read_table("target_file.parquet") # 提取所有Decimal类型列的信息 parquet_col_info = {} for field in parquet_table.schema: if pa.types.is_decimal(field.type): parquet_col_info[field.name] = { "precision": field.type.precision, "scale": field.type.scale }
如果需要转成Pandas DataFrame并保留Decimal类型,可以用convert_decimals=True参数:
import pandas as pd df = parquet_table.to_pandas(convert_decimals=True) # 验证列类型:此时Decimal列的类型为pd.DecimalDtype for col in df.columns: dtype = df[col].dtype if isinstance(dtype, pd.DecimalDtype): print(f"{col}: Decimal({dtype.precision}, {dtype.scale})")
2. 获取数据库的Schema信息
根据你使用的数据库类型,查询对应的系统表提取numeric/decimal列的精度和刻度。以下是两种常见数据库的示例:
PostgreSQL示例(用SQLAlchemy)
from sqlalchemy import create_engine, inspect # 初始化数据库连接 engine = create_engine("postgresql://user:password@host:port/db_name") inspector = inspect(engine) # 提取目标表的列信息 db_col_info = {} table_columns = inspector.get_columns("target_table") for col in table_columns: if col["type"].startswith("numeric") or col["type"].startswith("decimal"): # 解析numeric(38,22)格式的类型字符串 type_detail = col["type"].strip("()").split("(")[1].split(",") db_col_info[col["name"]] = { "precision": int(type_detail[0]), "scale": int(type_detail[1]) }
MySQL示例(用SQLAlchemy)
MySQL的系统表直接提供了精度和刻度的字段,无需解析字符串:
table_columns = inspector.get_columns("target_table") db_col_info = {} for col in table_columns: if col["type"].startswith("decimal"): db_col_info[col["name"]] = { "precision": col["numeric_precision"], "scale": col["numeric_scale"] }
3. 对比Parquet与数据库的Schema
将两者的列信息逐一匹配,验证精度和刻度是否一致:
# 遍历Parquet的Decimal列 for col_name, pq_type in parquet_col_info.items(): if col_name not in db_col_info: print(f"警告:列 {col_name} 在数据库中不存在") continue db_type = db_col_info[col_name] if pq_type["precision"] == db_type["precision"] and pq_type["scale"] == db_type["scale"]: print(f"列 {col_name}: 类型匹配 - Decimal({pq_type['precision']}, {pq_type['scale']})") else: print(f"错误:列 {col_name} 类型不匹配!Parquet是Decimal({pq_type['precision']}, {pq_type['scale']}),数据库是numeric({db_type['precision']}, {db_type['scale']})")
注意事项
- 确保Parquet文件在写入时保留了Decimal元数据:如果是用其他工具写入的Parquet,可能会把Decimal转成double,这种情况下无法恢复原始精度,需要检查写入时的配置(比如PyArrow写入时要指定
type=pa.decimal128(precision, scale))。 - 多数数据库中
numeric和decimal是同义词,对比时无需区分两者的名称。 - 不要用double类型来做对比:double是浮点数,无法精确表示Decimal的所有值,会导致精度丢失,完全不适合用来验证Schema。
内容的提问来源于stack exchange,提问作者ekm0d
相关产品推荐
相关产品推荐

