【问题标题】:How to increment the value of a variable in a loop for insert sql statement using pyodbc如何在循环中增加变量的值以使用 pyodbc 插入 sql 语句
【发布时间】:2019-06-18 19:30:26
【问题描述】:

我正在尝试从 API 中提取员工考勤卡数据,然后将其插入到 sql 数据库中。我希望代码查看数据,隔离特定日期的打卡和打卡,然后将它们插入到 sql 数据库中。唯一要注意的是,数据库需要一个序列号“SEQ_NO”来指示当天的哪个打卡时间要考虑休息、午餐等,所以我希望它循环将序列号增加 1 而不执行标题插入超过对同一员工执行一次(最终“kelly walton”和“080098”将被替换为变量,以便可以为数据集中的每个员工执行。

我已经尝试了几乎所有在堆栈溢出时发现的变量递增方法,但我无法让它工作。 for 循环,while 循环 if,elif 语句,你命名它,我什么也做不了。这只是代码的一个版本。为了澄清这个问题,无论我尝试使用哪种类型的循环,它都会尝试复制一些值,无论是标头查询还是打孔数据,都会导致 sql 数据库出错。

today = ('2019-06-05')
with open('timepunches.json', 'r') as f:
    timepunches_dict = json.load(f)
for punch in timepunches_dict:
    punch_in = punch['PunchInDateTime']
    punch_out = punch['PunchOutDateTime']
    punch_in_sql = punch_in.replace('T', ' ')
    punch_out_sql = punch_out.replace('T', ' ')
    if today in punch_in_sql:
        #print(punch_in_sql, punch_out_sql)
        cnx = pyodbc.connect('driver={SQL Server};server=MY_server;database=my_db;uid=****;pwd=****')
        cursor = cnx.cursor()
        sequence_number = 1
            if sequence_number == 1:
                sql_insert_header_query = ''' INSERT INTO my_db.dbo.SY_TIMCRD_HDR
                    (STR_ID, USR_ID, TIMCRD_DAT, USR_NAM) VALUES ('M-MAC', '080098', '2019-06-05 00:00:00.000', 'Kelly Walton')'''
                sql_timecard_data = '''INSERT INTO my_db.dbo.SY_TIMCRD_LIN
                    (STR_ID, USR_ID, TIMCRD_DAT, SEQ_NO, CLCK_IN_TIM) VALUES ('M-MAC', '080098', [dbo].[fnDateOnly]('%s'), '%s', [dbo].[fnTimeOnly]('%s'))'''
                cursor.execute(sql_insert_header_query)
                cursor.execute(sql_timecard_data % (today, sequence_number, punch_in_sql))
                sequence_number+=1
            elif sequence_number == 2:
                sql_timecard_data = '''INSERT INTO my_db.dbo.SY_TIMCRD_LIN
                    (STR_ID, USR_ID, TIMCRD_DAT, SEQ_NO, CLCK_OUT_TIM) VALUES ('M-MAC', '080098', [dbo].[fnDateOnly]('%s'), '%s', [dbo].[fnTimeOnly]('%s'))'''
                cursor.execute(sql_insert_header_query)
                cursor.execute(sql_timecard_data % (today, sequence_number, punch_out_sql))
                sequence_number+=1            
        cnx.commit()
        cnx.close()

我认为这会将 'sequence_number' 增加到 2 并执行下一部分。我打算在这部分工作后添加更多语句。

编辑:这是“timepunches.json”中的 JSON 数据,可能会有所帮助。

[{"JobCodeId": null, 
    "PunchInApprovalStatusId": 4, 
    "PunchInImageUrl": "", 
    "LocationName": "", 
    "PunchInNotes": "", 
    "PunchOutLongitude": null, 
    "PunchOutLatitude": null, 
    "Employee": 
        {"Username": "starlord", 
        "EmployeeId":"080097", 
        "FirstName": "Peter", 
        "LastName": "Quill", 
        "ProfileMiniImageUrl": "https://buddypunchapp.blob.core.windows.net/profileminipics/new_employee_face2.jpg", 
        "Email": "starlord@email.com", 
        "FullName": "Peter Quill", 
        "Id": 346968, 
        "IsActive": true}, 
    "PunchOutDateTime": "2019-06-10T10:00:00", 
    "BreakMinutes": 0, 
    "Hours": 2.0, 
    "PunchOutApprovalStatusName": "Changed By Manager", 
    "OverTimeHours": 0.0, 
    "DoubleTimeHours": 0.0, 
    "JobCodeName": "", 
    "PunchInIpAddress": "", 
    "PunchInApprovalStatusName": "Changed By Manager", 
    "PTOEarningCodeAbbr": "", 
    "PunchOutIpAddress": "", 
    "PunchOutImageUrl": "", 
    "PunchInLongitude": null, 
    "BreakApprovalStatusId": null, 
    "BreakApprovalStatusName": null, 
    "PTOHours": null, 
    "PunchOutApprovalStatusId": 4, 
    "PunchInDateTime": "2019-06-10T08:00:00", 
    "PunchOutNotes": "", 
    "PTOEarningCodeId": null, 
    "Id": 12971600, 
    "PunchInLatitude": null, 
    "LocationId": null, 
    "Duration": "02:00:00", 
    "RegularHours": 2.0}, 

    {"JobCodeId": null, 
    "PunchInApprovalStatusId": 4, 
    "PunchInImageUrl": "", 
    "LocationName": "", 
    "PunchInNotes": "", 
    "PunchOutLongitude": null, 
    "PunchOutLatitude": null, 
    "Employee": {
        "Username": "starlord", 
        "EmployeeId": "080097", 
        "FirstName": "Peter", 
        "LastName": "Quill", 
        "ProfileMiniImageUrl": "https://buddypunchapp.blob.core.windows.net/profileminipics/new_employee_face2.jpg", 
        "Email": "starlord@email.com", 
        "FullName": "Peter Quill", 
        "Id": 346968, 
        "IsActive": true}, 
    "PunchOutDateTime": "2019-06-10T12:00:00", 
    "BreakMinutes": 0, 
    "Hours": 1.75, 
    "PunchOutApprovalStatusName": "Changed By Manager", 
    "OverTimeHours": 0.0, 
    "DoubleTimeHours": 0.0, 
    "JobCodeName": "", 
    "PunchInIpAddress": "", 
    "PunchInApprovalStatusName": "Changed By Manager", 
    "PTOEarningCodeAbbr": "", 
    "PunchOutIpAddress": ", 
    "PunchOutImageUrl": "", 
    "PunchInLongitude": null, 
    "BreakApprovalStatusId": null, 
    "BreakApprovalStatusName": null, 
    "PTOHours": null, 
    "PunchOutApprovalStatusId": 4, 
    "PunchInDateTime": "2019-06-10T10:15:00", 
    "PunchOutNotes": "", 
    "PTOEarningCodeId": null, 
    "Id": 12971609, 
    "PunchInLatitude": null, 
    "LocationId": null, 
    "Duration": "01:45:00", 
    "RegularHours": 1.75}, 

    {"JobCodeId": null, 
    "PunchInApprovalStatusId": 4, 
    "PunchInImageUrl": "", 
    "LocationName": "", 
    "PunchInNotes": "", 
    "PunchOutLongitude": null, 
    "PunchOutLatitude": null, 
    "Employee": {
        "Username": "starlord", 
        "EmployeeId": "080097", 
        "FirstName": "Peter", 
        "LastName": "Quill", 
        "ProfileMiniImageUrl": "https://buddypunchapp.blob.core.windows.net/profileminipics/new_employee_face2.jpg", 
        "Email": "starlord@email.com", 
        "FullName": "Peter Quill", 
        "Id": 346968, 
        "IsActive": true}, 
    "PunchOutDateTime": "2019-06-10T15:00:00", 
    "BreakMinutes": 0, 
    "Hours": 2.0, 
    "PunchOutApprovalStatusName": "Changed By Manager", 
    "OverTimeHours": 0.0, 
    "DoubleTimeHours": 0.0, 
    "JobCodeName": "", 
    "PunchInIpAddress": "", 
    "PunchInApprovalStatusName": "Changed By Manager", 
    "PTOEarningCodeAbbr": "", 
    "PunchOutIpAddress": "", 
    "PunchOutImageUrl": "", 
    "PunchInLongitude": null, 
    "BreakApprovalStatusId": null, 
    "BreakApprovalStatusName": null, 
    "PTOHours": null, 
    "PunchOutApprovalStatusId": 4, 
    "PunchInDateTime": "2019-06-10T13:00:00", 
    "PunchOutNotes": "", 
    "PTOEarningCodeId": null, 
    "Id": 12971618, 
    "PunchInLatitude": null, 
    "LocationId": null, 
    "Duration": "02:00:00", 
    "RegularHours": 2.0}, 

    {"JobCodeId": null, 
    "PunchInApprovalStatusId": 4, 
    "PunchInImageUrl": "", 
    "LocationName": "", 
    "PunchInNotes": "", 
    "PunchOutLongitude": null, 
    "PunchOutLatitude": null, 
    "Employee": {
        "Username": "starlord", 
        "EmployeeId": "080097", 
        "FirstName": "Peter", 
        "LastName": "Quill", 
        "ProfileMiniImageUrl": "https://buddypunchapp.blob.core.windows.net/profileminipics/new_employee_face2.jpg", 
        "Email": "starlord@email.com", 
        "FullName": "Peter Quill", 
        "Id": 346968, 
        "IsActive": true}, 
    "PunchOutDateTime": "2019-06-10T17:00:00", 
    "BreakMinutes": 0, 
    "Hours": 1.75, 
    "PunchOutApprovalStatusName": "Changed By Manager", 
    "OverTimeHours": 0.0, 
    "DoubleTimeHours": 0.0, 
    "JobCodeName": "", 
    "PunchInIpAddress": "", 
    "PunchInApprovalStatusName": "Changed By Manager", 
    "PTOEarningCodeAbbr": "", 
    "PunchOutIpAddress": "", 
    "PunchOutImageUrl": "", 
    "PunchInLongitude": null, 
    "BreakApprovalStatusId": null, 
    "BreakApprovalStatusName": null, 
    "PTOHours": null, 
    "PunchOutApprovalStatusId": 4, 
    "PunchInDateTime": "2019-06-10T15:15:00", 
    "PunchOutNotes": "", 
    "PTOEarningCodeId": null, 
    "Id": 12971630, 
    "PunchInLatitude": null, 
    "LocationId": null, 
    "Duration": "01:45:00", 
    "RegularHours": 1.75}]

【问题讨论】:

  • 我会在 for 循环之外定义 cnx,因为每次迭代都重新建立连接效率很低
  • If/Elif 是“做这个或那个”,所以它是 1,它执行这个并将其增加到 2,循环的下一次迭代,它将它设置回 1 并检查它是否为 1再次...
  • 我肯定会在循环之外构建 cnx,这是一个很好的选择。但我更关心代码中被破坏的部分,我会更担心它工作后的效率。
  • @tgikal 你会如何建议执行我正在尝试做的事情?
  • 什么是[dbo].[fnDateOnly]?而且您没有解释当前代码有什么问题。你说我什么都做不了,但这是含糊的。这是否意味着没有或附加了错误的数据?

标签: python python-2.7 pyodbc


【解决方案1】:

考虑在循环期间使用enumerate() 对您的流程进行以下调整以获取序列号,重要的是使用parameterization 而不是字符串插值。

# VARIABLES
today = '2019-06-05'

# OPEN CONNECTION AND CURSOR
cnx = pyodbc.connect('driver={SQL Server};server=MY_server;database=my_db;uid=****;pwd=****')
cursor = cnx.cursor()

# PREPARED STATEMENTS
sql_insert_header_query = '''INSERT INTO my_db.dbo.SY_TIMCRD_HDR (STR_ID, USR_ID, TIMCRD_DAT, USR_NAM) 
                             VALUES ('M-MAC', ?, ?, ?)
                          '''

sql_timecard_data = '''INSERT INTO my_db.dbo.SY_TIMCRD_LIN (STR_ID, USR_ID, TIMCRD_DAT, SEQ_NO, CLCK_IN_TIM) 
                       VALUES ('M-MAC', ?, [dbo].[fnDateOnly](?), ?, [dbo].[fnTimeOnly](?))
                    '''

with open('timepunches.json', 'r') as f:
    timepunches_dict = json.load(f)

for i, punch in enumerate(timepunches_dict):
    punch_in = punch['PunchInDateTime']
    punch_out = punch['PunchOutDateTime']
    punch_in_sql = punch_in.replace('T', ' ')
    punch_out_sql = punch_out.replace('T', ' ')

    emp_id = punch['Employee']['EmployeeId']
    emp_name = punch['Employee']['FullName']

    if today in punch_in_sql:
        #print(punch_in_sql, punch_out_sql)

        if i == 0:
            # ONLY RUN FOR FIRST ITERATION 
            cursor.execute(sql_insert_header_query, (emp_id, today, emp_name))
            cnx.commit()     

        # RUN FOR ALL ITERATIONS
        cursor.execute(sql_timecard_data, (emp_id, today, i+1, punch_in_sql))        
        cnx.commit()

cursor.close()
cnx.close() 

Rextester Demo (减去数据库对象)

【讨论】:

  • 这在大多数情况下对我来说很有意义并且更简洁,但是,从 1 开始 i 的最佳方法是 0 是无效的 seq_no 以及我现在得到错误:Traceback (most recent call last): File "c:/Users/micah/Desktop/Buddy Punch/employeeget.py", line 96, in <module> cursor.execute(sql_insert_header_query, (emp_id, today, emp_name)) pyodbc.ProgrammingError: The cursor's connection has been closed. 这仍然执行标题查询和一个时间卡查询,但随后失败,我收到上述错误。
  • 查看编辑。无论出于何种原因,我昨晚对最后一条评论的编辑没有出现。显然 emp_idemp_name 可以在 json 中检索。我什至添加了一个在线演示,打印出要插入的数据。
  • 查看此更新 demo 添加另一个增量变量 j 和帮助器 curr_date。为了演示,我将最后两个 PunchInDateTime 更改为不同的日期:12 日。
  • 但原始解决方案保持if 条件以在当前日期选择:if today in punch_in_sql:
  • 这是因为之前的代码假定标题始终位于 json 的第一个字典中,无论日期如何。但是您以if today in punch_in_sql: 为条件。要修复,请忽略所有i 的使用(不再使用enumerate)并使用jif j == 1:rextester.com/GGB76730
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-24
  • 2011-07-04
  • 2020-05-23
  • 1970-01-01
  • 1970-01-01
  • 2018-04-22
相关资源
最近更新 更多