每日同步MS SQL中CRM数据至MySQL时遭遇主键重复错误求助
解决MS SQL到MySQL Upsert时的主键重复问题
嘿,看来你在做CRM数据跨库迁移的Upsert时踩了主键重复的坑,我来帮你拆解可能的原因和对应的解决办法:
1. 先确认你的Upsert逻辑是否真的生效了
Pandas自带的to_sql()默认是if_exists='append'模式,只会无脑插入新数据,根本不会处理主键重复的情况。如果你的Upsert逻辑只是简单调用这个方法,那出现主键重复错误简直是必然的。
给你一个靠谱的MySQL Upsert实现方案
用SQLAlchemy的核心语法来做Upsert会更稳妥,它能直接利用MySQL的ON DUPLICATE KEY UPDATE特性。示例代码如下:
from sqlalchemy import create_engine, Table, MetaData import pandas as pd # 初始化数据库连接 mssql_engine = create_engine('mssql+pyodbc://你的账号:密码@DSN名称') mysql_engine = create_engine('mysql+pymysql://你的账号:密码@主机地址/数据库名') metadata = MetaData() # 从MS SQL读取需要迁移的数据 df = pd.read_sql( "SELECT GUID, Name, favorite_number, modifiedon FROM CRM表名", mssql_engine ) # 加载MySQL目标表的结构 target_table = Table('你的MySQL表名', metadata, autoload_with=mysql_engine) # 构建Upsert语句:存在则更新,不存在则插入 insert_stmt = target_table.insert().values(df.to_dict('records')) upsert_stmt = insert_stmt.on_duplicate_key_update( Name=insert_stmt.inserted.Name, favorite_number=insert_stmt.inserted.favorite_number, modifiedon=insert_stmt.inserted.modifiedon ) # 执行Upsert操作 with mysql_engine.connect() as conn: conn.execute(upsert_stmt) conn.commit()
2. 检查GUID的格式是否完全一致
MS SQL的uniqueidentifier类型转成字符串后,通常是带连字符的大写格式(比如00000B9D-1234-5678-90AB-CDEF01234567),如果MySQL里存储的GUID是小写、去掉了连字符,或者格式有其他差异,就会导致Upsert时匹配失败——明明是同一个GUID,却被当成新数据插入,最终触发主键重复错误。
你可以这么排查:
- 打印Pandas DataFrame里的前几条GUID:
print(df['GUID'].head()) - 在MySQL里查询对应记录:
SELECT GUID FROM 你的MySQL表名 LIMIT 5; - 如果格式不一致,统一处理成和MySQL一致的格式,比如:
# 统一转小写并保留连字符 df['GUID'] = df['GUID'].str.lower() # 如果MySQL里是无连字符的格式,就替换掉: # df['GUID'] = df['GUID'].str.replace('-', '').str.lower()
3. 排查源数据是否真的存在重复GUID
虽然MS SQL的主键理论上不会重复,但CRM系统偶尔会出现历史数据导入错误的情况。你可以在MS SQL里跑这条SQL确认:
SELECT GUID, COUNT(*) AS 重复次数 FROM CRM表名 GROUP BY GUID HAVING COUNT(*) > 1;
如果查到重复数据,得先在源端清理干净再做迁移。
4. 确认MySQL表的主键约束配置正确
最后再检查一下MySQL表的结构,确保GUID字段确实被设置为主键,没有其他复合主键干扰。可以用这条SQL查看:
SHOW CREATE TABLE 你的MySQL表名;
确保输出里有PRIMARY KEY (GUID)的配置项。
内容的提问来源于stack exchange,提问作者Ben Dickson
相关产品推荐
相关产品推荐

