使用Python将Pandas DataFrame写入Teradata表时遇多方法报错求助
我尝试用Python把Pandas DataFrame写入Teradata表,试过teradatasql、pyodbc、sqlalchemy、teradata.UdaExec多种方法,但都报错,以下是各代码的问题及解决办法:
代码1:teradatasql + pandas.to_sql
host, user, password = 'SMASUN.UPC', 'J3E186', 'admin123' database, table_name = 'Supply', 'AD_Products' con = teradatasql.connect(host=host, user=user, password=password, database=database) sam = pd.read_csv("C:/Users/Desktop/products.csv") sam.to_sql(table_name, con=con, index=False, if_exists="replace")
错误信息:
OperationalError: [Version 17.20.0.19] [Session 34249729] [Teradata Database] [Error 3707] Syntax error, expected something like a 'CHECK' keyword between '(' and the 'exp' keyword.
问题原因:
pandas的to_sql在if_exists="replace"模式下自动生成的建表DDL和Teradata语法不兼容。错误里提到的exp大概率是DataFrame的列名,而exp是Teradata内置函数名,作为列名未加引号导致语法冲突;另外pandas生成的CHECK约束语法也不符合Teradata规范。
解决办法:
- 手动建表后追加数据:先在Teradata中手动创建和DataFrame结构完全匹配的
AD_Products表,再把if_exists改为"append",避开pandas自动生成建表语句:sam.to_sql(table_name, con=con, index=False, if_exists="append") - 转义保留字列名:如果有
exp这类保留字列名,给列名加双引号(Teradata用双引号识别带保留字的对象名),比如把DataFrame列名改为"exp"。 - 使用FastLoad批量加载:teradatasql原生支持FastLoad模式,兼容性和效率都比
to_sql好:with teradatasql.connect(host=host, user=user, password=password, database=database) as con: with con.cursor() as cur: # 先手动定义表结构 cur.execute(f"CREATE TABLE IF NOT EXISTS {table_name} (col1 VARCHAR(50), col2 INT, ...)") # 批量加载数据 cur.fastload(sam.to_records(index=False).tolist(), table_name)
代码2:sqlalchemy连接Teradata
tera_engine = create_engine('teradata://'+ user +':' + password + '@'+ host + ':22/') df = '`SELECT * FROM `fucntional_.supply.products`' # 想直接从BigQuery推到Teradata connection = tera_engine.connect() connection.execute(df) connection.close()
错误信息:
DatabaseError: (1207, '[HY000] [TPT][ODBC PostgreSQL Wire Protocol driver]Connection refused. Verify Host Name and Port Number., [TPT][ODBC PostgreSQL Wire Protocol driver]Invalid attribute in connection string: DBCNAME.')
问题原因:
- 连接字符串完全错误:Teradata默认端口是1025/1026,你误用了SSH的22端口;且未指定正确的Teradata驱动,导致系统误调用PostgreSQL驱动。
- 逻辑错误:Teradata无法直接访问BigQuery的表,直接执行BigQuery的SELECT语句行不通。
解决办法:
- 修正sqlalchemy连接配置:先安装
sqlalchemy-teradata包(pip install sqlalchemy-teradata),再用正确的连接格式:from sqlalchemy import create_engine tera_engine = create_engine(f"teradata://{user}:{password}@{host}:1025/{database}?driver=Teradata") - 正确跨库迁移逻辑:先把BigQuery的数据读到本地DataFrame,再写入Teradata:
# 从BigQuery取数到DataFrame(示例) from google.cloud import bigquery bq_client = bigquery.Client() query = "SELECT * FROM functional_.supply.products" df = bq_client.query(query).to_dataframe() # 写入Teradata df.to_sql(table_name, con=tera_engine, index=False, if_exists="replace", method="multi")
代码3:pyodbc executemany插入
df = pd.read_csv("C:/Users/Desktop/products.csv") table_name = 'products' insert_query = f"insert into {table_name} values (?, ?)" values = [tuple(row) for row in df.values.tolist()] cursor.executemany(insert_query, values) con.commit() con.close()
错误信息:
InterfaceError: ('28000', '[28000] [Teradata][ODBC Teradata Driver][Teradata Database] (210) The UserId, Password or Account is invalid.FailCode = -8017 (210)')
问题原因:
- 未正确建立数据库连接:代码未展示
con和cursor的创建过程,大概率是连接参数错误(用户名/密码/数据库名),或cursor未关联有效连接。 - 插入语句占位符数量与DataFrame列数不匹配:你写了
(?, ?),如果DataFrame列数不是2,后续会触发新错误(当前先解决认证问题)。
解决办法:
- 建立正确的pyodbc连接:
import pyodbc conn_str = ( f"DRIVER={{Teradata}};" f"DBCNAME={host};" f"UID={user};" f"PWD={password};" f"DATABASE={database};" ) con = pyodbc.connect(conn_str) cursor = con.cursor() # 必须从有效连接创建cursor - 动态生成占位符:根据DataFrame列数自动生成占位符,避免列数不匹配:
placeholders = ', '.join(['?' for _ in df.columns]) insert_query = f"INSERT INTO {table_name} VALUES ({placeholders})" - 验证账户权限:确认用户名/密码正确,该账户有目标数据库的读写权限,必要时在连接字符串中添加
ACCOUNT参数。
内容的提问来源于stack exchange,提问作者s nandan

