【问题标题】:Deleting rows from an access table based on multiple conditions in python along with a date field根据python中的多个条件以及日期字段从访问表中删除行
【发布时间】:2018-09-14 17:44:00
【问题描述】:

我正在尝试从 access 数据库表中删除行,基于两列,一列是 release_by 和 release_date。

Sudo code

WHERE released_by  = '27' and released_date would change based on the day of the month. 

Released_Date 如果 day ==1 然后删除上个月的数据,否则删除当前月份的数据。

import pandas as pd
import numpy as np
import datetime
from datetime import date
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
import pyodbc
import calendar
import xlrd
import defusedxml
from defusedxml.common import EntitiesForbidden
from xlrd import open_workbook
defusedxml.defuse_stdlib()

# connecting to access database
conn = pyodbc.connect(r'Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=C:\Users\Desktop\Insights.accdb;')
insights_dbcurs = conn.cursor()

select_auto_releases = "SELECT * FROM RELEASES WHERE RELEASED_BY = '27'"
autoreleases = insights_dbcurs.execute(select_auto_releases).fetchall()
#display(autoreleases)

for row in autoreleases:
    previousmonth = datetime.now() - relativedelta(months=1)
    previousmonth = previousmonth.strftime("%m - %Y")
    currentmonth = datetime.now()
    currentmonth = currentmonth.strftime("%m - %Y")
    if ((row.autoreleases['RELEASED_DATE']).strftime) ==1:
        try:
            delete = 'DELETE * FROM RELEASES WHERE RELEASED_DATE = ? and RELEASED_BY = ?'
            insights_dbcurs.execute(delete,{'RELEASED_DATE':currentmonth},{'RELEASED_BY':'27'})
        except:
            delete = 'DELETE * FROM RELEASES WHERE RELEASED_DATE = ? and RELEASED_BY = ?'
            insights_dbcurs.execute(delete,{'RELEASED_DATE':previousmonth},{'RELEASED_BY':'27'})

insights_dbcurs.close()
conn.commit()
conn.close()

它不起作用。我明白了:

AttributeError: 'pyodbc.Row' 对象没有属性 'autoreleases'

如果我删除Row.autorelease,我会得到

sql有0个属性,2个被传递。

我该如何避免这种情况。任何建议都会很有帮助。

【问题讨论】:

  • 试试if ((row.RELEASED_DATE).strftime) ==1:
  • @GordThompson 谢谢我试过了。我现在在运行代码时注意到 RELEASED_DATE 被作为字符串拉入。 'AttributeError: 'str' object has no attribute 'strptime' or strftime '。当我尝试将其转换为日期格式时。我也试过 .((row.RELEASED_DATE).astype(date).strftime ==1它也没有用。上述的工作与这个新的后果不同。
  • 如果row.RELEASED_DATE 是一个字符串,那么要么使用.strptime(...) 解析它,然后使用.strftime("%m - %Y") 重新格式化它,或者只使用字符串操作来重新排列子字符串部分以匹配@ 987654330@
  • 因为我使用当前日期来检查要删除哪个月份的数据,所以我将其更改为if datetime.now().strftime('%d') !=1:`try:`delete = 'DELETE * FROM RELEASES WHERE RELEASED_DATE = ? and RELEASED_BY = ?'insights_dbcurs.execute(delete,{'RELEASED_DATE':currentmonth},{'RELEASED_BY':'27'})`但是我得到了这个SystemError: <class 'pyodbc.ProgrammingError'> returned a result with an error set。执行语句附近的错误点。

标签: python sql ms-access pyodbc


【解决方案1】:

考虑针对几个问题重构您的代码:

  1. try/except 通常用于处理运行时异常和错误,而不是应用程序逻辑。在这些情况下使用if/else

  2. 删除不需要的 for 循环,因为您不会逐行删除,因为没有唯一标识符被传递到 DELETE 语句中。实际上,如果逻辑将未过滤的当前行传递给该行,则您正在跨整个表运行删除过程。

  3. 将纯 SQL 与一个 DELETE 语句一起使用,避免 Python 处理时间元素,如您所见,这会维护数据库的转换问题。 MS Access SQL 确实具有日期函数,例如 Date()(当前日期)和 DatePart() 用于月/日提取。此外,MS Access 可以DELETE 中运行复杂的子查询逻辑。

SQL

对两个日期条件都使用IN 子查询。注意:ID 应替换为表的唯一标识符。在DELETE 版本之前检查SELECT 查询版本。

DELETE FROM RELEASES r
WHERE r.ID IN
  (SELECT sub.ID  
   FROM RELEASES sub
   WHERE sub.RELEASED_BY = ? 
     AND (
           (
            DatePart('m', sub.RELEASED_DATE) = DatePart('m', Date()) - 1
            AND DatePart('yyyy', sub.RELEASED_DATE) = DatePart('yyyy', Date())
            AND DatePart('d', sub.RELEASED_DATE) = 1
           )
          OR 
           (
            DatePart('m', sub.RELEASED_DATE) = DatePart('m', Date())
            AND DatePart('yyyy', sub.RELEASED_DATE) = DatePart('yyyy', Date())
            AND DatePart('d', sub.RELEASED_DATE) > 1
           )
        )
  )

Python

使用 Access 引擎中处理的日期传递参数。

conn = pyodbc.connect(r'...')
insights_dbcurs = conn.cursor()

sql = """DELETE FROM RELEASES r
         WHERE r.ID IN
           (SELECT sub.ID 
            FROM RELEASES sub
            WHERE sub.RELEASED_BY = ? 
              AND (
                    (
                     DatePart('m', sub.RELEASED_DATE) = DatePart('m', Date()) - 1
                     AND DatePart('yyyy', sub.RELEASED_DATE) = DatePart('yyyy', Date())
                     AND DatePart('d', sub.RELEASED_DATE) = 1
                    )
                   OR 
                    (
                     DatePart('m', sub.RELEASED_DATE) = DatePart('m', Date())
                     AND DatePart('yyyy', sub.RELEASED_DATE) = DatePart('yyyy', Date())
                     AND DatePart('d', sub.RELEASED_DATE) > 1
                    )
                  )
           )"""

insights_dbcurs.execute(sql, ('27',))
conn.commit()
conn.close()

【讨论】:

  • 感谢您的修改。我已经尝试过相同的方法并继续在执行部分出现错误。 ProgrammingError: ('42000', "[42000] [Microsoft][ODBC Microsoft Access Driver] Invalid use of '.', '!', or '()'. in query expression 'SUB.RELEASED_BY = Pa_RaM000\n AND \n (\n (DatePart('m',SUB.RELEASED_DATE) = DatePart('m'.Date())-1\n AND DatePart('d',SUB.RELEASED'. (-3100) (SQLExecDirectW)").
  • 似乎是缺少括号的问题,但我看不到。我刚刚将此查询复制到 MS Access 中,它保存没有问题。 Access 不会保存带有语法错误的查询。您是否在 Python 中的任何地方对这篇文章进行了任何更改?我看到 Pa_RaM000。这是一个参数吗?
  • 这个建议在这种情况下可能特别有用,因为 Access 在类型杂耍方面往往更加适应。例如,Access 会自动转换一个类似日期的字符串来代替真实日期(例如,DatePart("m", "2018-09-12") 有效),而 Python 对此类事情要严格得多(例如,d.month 有效,如果 d 是 @ 987654339@ 但如果dstr 则不是)。
  • @Parfait - Pa_RaM000 是 Jet/ACE 准备语句时查询参数的内部表示。它也可以在 Jet/ACE SHOWPLAN 输出中找到。
  • 我再次检查了没有缺少括号。当我最后使用“27”时,这个 Pa_RaM000 就来了。我没有添加任何额外的东西。如果我使用“?”然后我得到错误SQL has 0 parameters 2 parameters being passed.
猜你喜欢
  • 2020-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多