【问题标题】:Python Read a CSV and place values in MySQL DatabasePython 读取 CSV 并将值放入 M​​ySQL 数据库
【发布时间】:2013-02-10 10:38:45
【问题描述】:

我正在尝试从 csv 获取值并将它们放入数据库中,我设法做到这一点没有很多麻烦。

但我知道需要写回 csv,所以下次我运行脚本时,它只会将值从 csv 文件中的标记处输入到数据库中。

请注意,系统上的 CSV 文件每 24 小时自动刷新一次,因此请注意 csv 中可能没有标记。所以基本上如果没有找到标记就把所有的值都放到数据库中。

我计划每 30 分钟运行一次此脚本,因此 csv 文件中可能有 48 个标记,甚至每次都删除标记并将其移到文件中?

我一直在删除文件,然后在脚本中重新创建一个文件,因此每个脚本都会运行新文件,但这会以某种方式破坏系统,因此这不是一个好的选择。

希望各位大侠能帮忙..

谢谢

Python 代码:

import csv
import MySQLdb

mydb = MySQLdb.connect(host='localhost',
user='root',
passwd='******',
db='kestrel_keep')

cursor = mydb.cursor()

csv_data = csv.reader(file('data_csv.log'))

for row in csv_data:

    cursor.execute('INSERT INTO `heating` VALUES ( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,)',
   row)
#close the connection to the database.
mydb.commit()
cursor.close()
import os


print "Done"

我的 CSV 文件格式:

2013-02-21,21:42:00,-1.0,45.8,27.6,17.3,14.1,22.3,21.1,1,1,2,2
2013-02-21,21:48:00,-1.0,45.8,27.5,17.3,13.9,22.3,20.9,1,1,2,2

【问题讨论】:

    标签: python mysql csv import


    【解决方案1】:

    我认为比“标记”CSV 文件更好的选择是保留一个文件,如果您存储了您处理的最后一行的编号。

    因此,如果文件不存在(您存储最后处理的行号的文件),则处理整个 CSV 文件。如果此文件存在,您只处理此行之后的记录。

    工作系统的最终代码:

    #!/usr/bin/python
    import csv
    import MySQLdb
    import os
    
    mydb = MySQLdb.connect(host='localhost',
    user='root',
    passwd='*******',
    db='kestrel_keep')
    
    cursor = mydb.cursor()
    
    csv_data = csv.reader(file('data_csv.log'))
    
    start_row = 0
    
    def getSize(fileobject):
    fileobject.seek(0,2) # move the cursor to the end of the file
    size = fileobject.tell()
    return size
    
    file = open('data_csv.log', 'rb')
    curr_file_size = getSize(file)
    
    # Get the last file Size
    if os.path.exists("file_size"):
    with open("file_size") as f:
        saved_file_size = int(f.read())
    
    
    # Get the last processed line
    if os.path.exists("lastline"):
    with open("lastline") as f:
        start_row = int(f.read())
    
    
    if curr_file_size < saved_file_size: start_row = 0
    
    cur_row = 0
    for row in csv_data:
     if cur_row >= start_row:
         cursor.execute('INSERT INTO `heating` VALUES ( %s, %s, %s, %s, %s, %s, %s, %s, %s,    %s, %s, %s, %s, %s, %s, %s ,%s)', row)
    
         # Other processing if necessary
    
     cur_row += 1
    
     mydb.commit()
     cursor.close()
    
    
    # Store the last processed line
    with open("lastline", 'w') as f:
    start_line = f.write(str(cur_row + 1)) # you want to start at the **next** line
                                          # next time
    # Store Current  File Size To Find File Flush    
    with open("file_size", 'w') as f:
    start_line = f.write(str(curr_file_size))
    
    # not necessary but good for debug
    print (str(cur_row))
    
    
    
     print "Done"
    

    编辑: 最终代码由 ZeroG 提交,现在正在系统上运行!!也感谢 Xion345 的帮助

    【讨论】:

    • 我喜欢这个答案,但我无法得到我们要放入最后一行文件中的行号 0 甚至 '(str(cur_row))' 辱骂 0... 在文件被刷新时也要记住在 00:01:00 行 no 不会与新的 csv 文件相关,所以我想我们需要在某处检查时间
    • 是的,你是对的代码是错误的,你需要在for循环的末尾移动cur_row += 1语句。至于00:01的flush,需要查看当前时间和最后一行文件的写入日期。
    • @ZeroG :检测文件是否已刷新的更好方法是将 CSV 文件的大小存储在最后一行文件中(除了最后处理的行之外)。如果在脚本的两次后续执行之间文件大小有所减小,则您知道 CSV 文件已被刷新。
    • 好的,所以我们基本上让脚本运行,每次我运行脚本时都会在最后一行的行数上加 1,因此第一次 1 第二次 = 2 在行数 = 1 之后什么都没有在数据库中对不起我在这里遗漏了什么?
    • @ZeroG :每次运行脚本时,最后一行的编号+1都会写入最后一行文件。例如,如果第一次运行脚本时 CSV 文件中有 15 行,则最后处理的行是第 14 行,因此 15 将被写入最后一行文件。如果第二次运行脚本时有 100 行,将跳过第 0-14 行,将处理第 15-99 行,并将第 100 行写入最后一行文件等...
    【解决方案2】:

    每个 csv 行似乎都包含一个时间戳。如果这些总是在增加,您可以在数据库中查询已记录的最大时间戳,并在读取 csv 时跳过该时间之前的所有行。

    【讨论】:

      【解决方案3】:

      您的 MySQL 表中的第一个字段似乎是一个唯一时间戳。可以设置 MySQL 表,使字段必须是唯一的,并忽略会违反该唯一性属性的 INSERTs。在mysql&gt; 提示符下输入命令:

      ALTER IGNORE TABLE heating ADD UNIQUE heatingidx (thedate, thetime)    
      

      (将thedate 和thetime 更改为包含日期和时间的列的名称。)


      一旦对数据库进行了此更改,您只需在程序中更改一行即可使 MySQL 忽略重复插入:

      cursor.execute('INSERT IGNORE INTO `heating` VALUES ( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,)', row)
      

      是的,在已经处理过的线路上运行INSERT IGNORE ... 有点浪费,但考虑到数据的频率(每 6 分钟一次?),就性能而言,这并不重要。

      这样做的好处是现在不可能意外地将重复项插入到您的表中。它还使您的程序逻辑简单易读。

      它还避免了两个程序同时写入同一个 CSV 文件。即使您的程序通常成功且没有错误,但每隔一段时间——也许是千载难逢——你的程序和其他程序可能会尝试同时写入文件,这可能会导致在错误或损坏的数据中。


      您还可以使用cursor.executemany 代替cursor.execute 使您的程序更快一点:

      rows = list(csv_data)
      cursor.executemany('''INSERT IGNORE INTO `heating` VALUES
          ( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,)''', rows)
      

      等价于

      for row in csv_data:    
          cursor.execute('INSERT INTO `heating` VALUES ( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,)',
         row)
      

      除了它将所有数据打包到一个命令中。

      【讨论】:

      • @ZeroG:没问题。只需列出定义唯一行所需的所有字段。我已经编辑了上面的帖子以说明我的意思。
      • 这是否会考虑到日期和时间需要不同,即在 2 天内有 2 个 14:00,即使日期会不同?
      • 是的。只有当它们共享同一天和同一时间时,两行才会被视为相同。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-13
      • 2019-05-17
      • 1970-01-01
      • 2020-09-09
      • 1970-01-01
      • 2019-05-15
      • 2016-07-08
      相关资源
      最近更新 更多