用 Python 在 MS Access 数据库中插入或更新行

Posted

技术标签:

【中文标题】用 Python 在 MS Access 数据库中插入或更新行【英文标题】:Insert or update rows in MS Access database in Python 【发布时间】:2019-05-02 15:29:39 【问题描述】:

我有一个 MS Access 表 (SearchAdsAccountLevel),需要经常从 python 脚本更新。我已经建立了 pyodbc 连接,现在我想根据 Date_ 和 CampaignId 字段是否与 df 数据匹配,将我的 pandas df 中的行更新/插入到 MS Access 表中。

查看前面的示例,我构建了 UPDATE 语句,该语句使用 iterrows 遍历 df 中的所有行并按以下方式执行 SQL 代码:

    connection_string = (
            r"Driver=Microsoft Access Driver (*.mdb, *.accdb);"
            r"c:\AccessDatabases\Database2.accdb;"
    )
    cnxn = pyodbc.connect(connection_string, autocommit=True)
    crsr = cnxn.cursor()

    for index, row in df.iterrows():
            crsr.execute("UPDATE SearchAdsAccountLevel SET [OrgId]=?, [CampaignName]=?, [CampaignStatus]=?, [Storefront]=?, [AppName]=?, [AppId]=?, [TotalBudgetAmount]=?, [TotalBudgetCurrency]=?, [DailyBudgetAmount]=?, [DailyBudgetCurrency]=?, [Impressions]=?, [Taps]=?, [Conversions]=?, [ConversionsNewDownloads]=?, [ConversionsRedownloads]=?, [Ttr]=?, [LocalSpendAmount]=?, [LocalSpendCurrency]=?, [ConversionRate]=?, [Week_]=?, [Month_]=?, [Year_]=?, [Quarter]=?, [FinancialYear]=?, [RowUpdatedTime]=? WHERE [Date_]=? AND [CampaignId]=?",
                        row['OrgId'],
                        row['CampaignName'],
                        row['CampaignStatus'],
                        row['Storefront'],
                        row['AppName'],
                        row['AppId'],
                        row['TotalBudgetAmount'],
                        row['TotalBudgetCurrency'],
                        row['DailyBudgetAmount'],
                        row['DailyBudgetCurrency'],
                        row['Impressions'],
                        row['Taps'],
                        row['Conversions'],
                        row['ConversionsNewDownloads'],
                        row['ConversionsRedownloads'],
                        row['Ttr'],
                        row['LocalSpendAmount'],
                        row['LocalSpendCurrency'],
                        row['ConversionRate'],
                        row['Week_'],
                        row['Month_'],
                        row['Year_'],
                        row['Quarter'],
                        row['FinancialYear'],
                        row['RowUpdatedTime'],
                        row['Date_'],
                        row['CampaignId'])
crsr.commit()

我想遍历我的 df 中的每一行(大约 3000),如果 ['Date_'] AND ['CampaignId'] 匹配我更新所有其他字段。否则我想在我的访问表中插入整个 df 行(创建新行)。实现这一目标最有效和最有效的方法是什么?

【问题讨论】:

有很多方法和步骤来冒犯您的问题。 1-不要一一执行查询,使用参数化查询。 2- 在 python 中使用 yield's ... @Ilmari - 完成。感谢您的提醒。 【参考方案1】:

考虑DataFrame.values 并将列表传递给executemany 调用,确保为UPDATE 查询相应地对列进行排序:

cols = ['OrgId', 'CampaignName', 'CampaignStatus', 'Storefront',
        'AppName', 'AppId', 'TotalBudgetAmount', 'TotalBudgetCurrency',
        'DailyBudgetAmount', 'DailyBudgetCurrency', 'Impressions',
        'Taps', 'Conversions', 'ConversionsNewDownloads', 'ConversionsRedownloads',
        'Ttr', 'LocalSpendAmount', 'LocalSpendCurrency', 'ConversionRate',
        'Week_', 'Month_', 'Year_', 'Quarter', 'FinancialYear',
        'RowUpdatedTime', 'Date_', 'CampaignId']

sql = '''UPDATE SearchAdsAccountLevel 
            SET [OrgId]=?, [CampaignName]=?, [CampaignStatus]=?, [Storefront]=?, 
                [AppName]=?, [AppId]=?, [TotalBudgetAmount]=?, 
                [TotalBudgetCurrency]=?, [DailyBudgetAmount]=?, 
                [DailyBudgetCurrency]=?, [Impressions]=?, [Taps]=?, [Conversions]=?, 
                [ConversionsNewDownloads]=?, [ConversionsRedownloads]=?, [Ttr]=?, 
                [LocalSpendAmount]=?, [LocalSpendCurrency]=?, [ConversionRate]=?,
                [Week_]=?, [Month_]=?, [Year_]=?, [Quarter]=?, [FinancialYear]=?, 
                [RowUpdatedTime]=? 
          WHERE [Date_]=? AND [CampaignId]=?'''

crsr.executemany(sql, df[cols].values.tolist())   
cnxn.commit()

对于插入,使用具有精确结构的临时临时表作为最终表,您可以使用生成表查询创建该表:SELECT TOP 1 * INTO temp FROM final。该临时表将定期清理并插入所有数据框行。最终查询仅使用NOT EXISTS, NOT IN, or LEFT JOIN/NULL 将新行从 temp 迁移到 final。您可以随时运行此查询,而不必担心每个 Date_CampaignId 列的重复。

# CLEAN OUT TEMP
sql = '''DELETE FROM SearchAdsAccountLevel_Temp'''
crsr.executemany(sql)   
cnxn.commit()

# APPEND TO TEMP
sql = '''INSERT INTO SearchAdsAccountLevel_Temp (OrgId, CampaignName, CampaignStatus, Storefront,
                                AppName, AppId, TotalBudgetAmount, TotalBudgetCurrency,
                                DailyBudgetAmount, DailyBudgetCurrency, Impressions,
                                Taps, Conversions, ConversionsNewDownloads, ConversionsRedownloads,
                                Ttr, LocalSpendAmount, LocalSpendCurrency, ConversionRate,
                                Week_, Month_, Year_, Quarter, FinancialYear,
                                RowUpdatedTime, Date_, CampaignId)    
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 
                 ?, ?, ?, ?, ?, ?, ?, ?, ?, 
                 ?, ?, ?, ?, ?, ?, ?, ?, ?);'''

crsr.executemany(sql, df[cols].values.tolist())   
cnxn.commit()

# MIGRATE TO FINAL
sql = '''INSERT INTO SearchAdsAccountLevel 
         SELECT t.* 
         FROM SearchAdsAccountLevel_Temp t
         LEFT JOIN SearchAdsAccountLevel f
            ON t.Date_ = f.Date_ AND t.CampaignId = f.CampaignId
         WHERE f.OrgId IS NULL'''
crsr.executemany(sql)   
cnxn.commit()

【讨论】:

如何集成插入查询来创建当前不在我的表中但在 df 中的行? 这是一个不同的问题,因为它涉及不同的查询和数据处理。通常,暂存临时表用于避免在 INSERT...SELECT 调用中针对最终表附加带有 NOT IN, NOT EXISTS, LEFT JOIN/IS NULL 子句的重复项。 +1 表示df[cols].values 提示。公平地说,“插入”方面是问题的一部分(尽管隐藏在底部附近),this answer 通过对the dup 的评论涵盖了这一点。 您的一个或多个数据框列类型与数据库表类型不匹配。尝试使用read_sql 导入几行的select 查询,并将dtypes 与您当前的df 进行比较。 您需要在最后一个追加查询的INSERTSELECT 子句中明确命名列。对于后者,不要使用缩写*

以上是关于用 Python 在 MS Access 数据库中插入或更新行的主要内容,如果未能解决你的问题,请参考以下文章

使用 Python 在 MS Access 中传输数据

如何通过 Python 3.5.1 创建永久 MS Access Query?

如何在 Python 中转换、排序和保存到 CSV MS Access 数据库 .mdb 文件

如何在python中的字符串之间添加空格。我正在从 ms access 数据库中获取数据

使用 Python 为 MS Access .accdb 文件运行宏

使用 python 将 pandas 数据框导入 MS Access 表