SQLalchemy未知值的重复条目错误

1 投票
1 回答
643 浏览
提问于 2025-04-17 15:08

我正在写一个脚本,用来同步Adwords账户和本地数据库,使用的是Sqlalchemy这个工具。为了方便,我按照Adwords API的对象层级来设计我的数据库,所以我第一个表叫做'campaigns'(广告系列),第二个表叫做'adgroups'(广告组)。

下面是我如何定义这两个表的:

class Campaign(Base):

__tablename__ = 'aw_campaigns'

id = Column(Integer, primary_key=True)
name = Column(String(99))
impressions = Column(Integer)
serving_status = Column(String(99))
start_date = Column(String(99))
status = Column(String(99))

def __init__(self, id, name, impressions, serving_status, start_date, status):
    self.id = id
    self.name = name
    self.impressions = impressions
    self.serving_status = serving_status
    self.start_date = start_date
    self.status = status

class Adgroup(Base):

__tablename__ = 'aw_adgroups'

id = Column(Integer, primary_key=True)  # , primary_key=True
name = Column(String(99))
camp_id = Column(Integer, ForeignKey('aw_campaigns.id'))  # , ForeignKey('aw_campaigns.id')
camp_name = Column(String(99))
ctr = Column(Float)
cost = Column(Float)
impressions = Column(Integer)
clicks = Column(Integer)
status = Column(String(99))

def __init__(self, id, name, camp_id, camp_name, ctr, cost, impressions, clicks, status):
    self.id = id
    self.name = name
    self.camp_id = camp_id
    self.camp_name = camp_name
    self.ctr = ctr
    self.cost = cost
    self.impressions = impressions
    self.clicks = clicks
    self.status = status

我从API中查询数据,然后为Adgroup表中的每一行构建一个对象列表:

adgr_query = 'SELECT CampaignId, CampaignName, Clicks, Cost, Impressions, Ctr, Id, KeywordMaxCpc, Name, Settings, Status'
adgr_page = ad_group_serv.Query(adgr_query)[0]['entries']

adgr_ins = [Adgroup(i['id'],
            i['name'],
            i['campaignId'],
            i['campaignName'],
            i['stats']['ctr'],
            i['stats']['cost']['microAmount'],
            i['stats']['impressions'],
            i['stats']['clicks'],
            i['status']) for i in adgr_page if int(i['id']) not in adgr_exist]

但是当我提交数据时,出现了一个错误:

 (IntegrityError) (1062, "Duplicate entry '2147483647' for key 'PRIMARY'")

问题是我完全不知道这个值是从哪里来的。

'2147483647' in [i['id'] for i in adgr_page]
>>> False
'2147483647' in str(adgr_page)
>>> False

我现在真的卡住了。

1 个回答

1

看起来你在某个地方遇到了整数溢出的问题。

症状是:2147483647是2的31次方减去1,这说明你用32位来存储这个数字。

AdGroup.Id字段的类型是xsd:long,它的长度是64位。

Python本身对整数的大小没有限制,但数据库可能会有限制。

简单解决方案:

试着使用BigInteger作为sqltype类型,像这样写:id = Column(BigInteger, primary_key=True),对于camp_id和其他来自AdWords API的xsd:long值也是一样。这样SQLAlchemy可能会选择数据库特定的大整数列类型。或者你可以把id的类型设置为String(64)。不过这样的话,你需要额外的步骤来生成主键。

你的AdWords API查询返回了多少条记录?是否超过了2的32次方的记录?我对此表示怀疑,因为你的数据库不太可能处理大约42亿条记录。

长期解决方案

虽然我建议不要把主键的完整性依赖于外部来源,而是依靠数据库自动生成主键,并让SQLAlchemy根据数据库生成的主键来处理外键的填充:

class Adgroup(Base):
    __tablename__ = 'aw_adgroups'
    id = Column(Integer, Sequence('adgroup_seq'), primary_key=True)  # , primary_key=True
    adGroupId = Column(String(64)) 
    campaignId = Column(Integer,ForeignKey('aw_campaigns.id'))
    campaign = relationship("Campaign", backref = "adgroup")
    ...

class Campaign(Base):
    __tablename__ = 'aw_campaigns'
    id = Column(Integer, Sequence('adgroup_seq'), primary_key=True)
    campaignId = Column(String(64))
    ...

看起来你可能还需要通过campaignId和adGroupId进行查找,所以你可以在它们上面添加索引。

然后你可以创建你的Campaign和AdGroup对象,并在它们之间添加关系。具体的代码会根据你想要使用的关系类型而有所不同——是一对多还是多对多。更多细节可以查看sqlalchemy关系手册

ag = AdGroup(**kwargs)
camp = Campaign(**kwargs)
ag.campaign = camp
session.add(ag)

撰写回答