Python вызывает ошибку (недостаточно параметров для оператора SQL), когда CSV все еще загружается данными - PullRequest
1 голос
/ 07 мая 2020

Идея:

Моя цель - найти изменения в CSV, используя количество обнаруженных строк, и сравнить новое значение со старым значением. Если есть изменение, отправьте все данные CSV в таблицу MySQL.

Проблема

Прежде всего, код отлично работает, когда файл CSV не тронут и заполнен данными.

Но у нас есть программное обеспечение, которое загружает тысячи данных в CSV (загрузка всех данных в CSV занимает около 1 минуты). Каждый раз, когда программа запускается, она удаляет текущие данные и снова загружает новые.

Пока программа загружает данные в файл CSV, Python затем обнаруживает изменение в CSV и выдает мне эту ошибку :

Traceback (most recent call last):
  File "C:\Users\LV98\Desktop\Database Test\Database.py", line 83, in <module>
    start()
  File "C:\Users\LV98\Desktop\Database Test\Database.py", line 72, in start
    mySQLcursor2.execute('insert into fms (customer_code,customer_logo, product_code,product_description,allergen_info, barcode_inner, barcode_outer, ingredients, EnergyKJ, EnergyKCAL, Fat, Saturates, Carbohydrates, Sugars, Fibre, Protein, salt) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s);', row)
  File "C:\Users\LV98\AppData\Roaming\Python\Python38\site-packages\mysql\connector\cursor.py", line 558, in execute
    stmt = RE_PY_PARAM.sub(psub, stmt)
  File "C:\Users\LB98\AppData\Roaming\Python\Python38\site-packages\mysql\connector\cursor.py", line 85, in __call__
    raise errors.ProgrammingError(
mysql.connector.errors.ProgrammingError: Not enough parameters for the SQL statement

Но если я запускаю сценарий .py после того, как данные CSV все еще загружены - он работает нормально.

Обычно этот скрипт не работает при загрузке данных CSV.

Код:

def countRows():
    prev_rowcount_CSV = None
    while True:
        ###CSV
        file = open('C:/Users/LV98/Desktop/Database Test/FMSExport.csv')
        reader = csv.reader(file)
        lines = len(list(reader))

        if lines != prev_rowcount_CSV and prev_rowcount_CSV != None:
            print("CSV Change")
            #Truncate FMS table in MySQL database
            truncateFMS()

            mySQLcursor1 = mysqlConnection.cursor()
            with open('G:/Technical/Labels/Production/Data/FMSExport.csv', 'r') as f:
                data = csv.reader(f)
                next(data, None)
                for row in data:
                    mySQLcursor1.execute('insert into fms (customer_code,customer_logo, product_code,product_description,allergen_info, barcode_inner, barcode_outer, ingredients, EnergyKJ, EnergyKCAL, Fat, Saturates, Carbohydrates, Sugars, Fibre, Protein, salt) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s);', row)
            mysqlConnection.commit()
            mySQLcursor1.close()

            prev_rowcount_CSV = lines

            #Repeat this function every X seconds
            time.sleep(10 - ((time.time() - starttime) % 10))

countRows()

Вопрос:

Я бы хотел, чтобы этот код работал, даже когда данные CSV все еще загружаются с данными. Как заставить работать?

Ответы [ 2 ]

1 голос
/ 19 мая 2020

Проблема связана с чтением и записью в один и тот же файл одновременно.

Из ваших комментариев repeat this function every X seconds и
approx 1 Minute to load all data и
deletes the current data and loads the new
Звучит , в значительной степени, гарантировал , что в то время, когда ваш l oop генерирует sql операторы, файл, из которого он читает данные, изменится? Таким образом, будет прочитана неполная строка, что приведет к ошибке.

Возможные варианты:

  1. Изменять имя файла при каждой записи. Кажется, вы предлагаете это вне вашего контроля. Возможно, вы захотите вернуться к нему, потому что это самое простое и, пожалуй, самое разумное решение. Или

  2. Отделить запись файла от обработки файла. Например, действительно ли время между записями достаточно велико для копирования файла? Если да, то сделайте это, а затем обработайте копию. Возможно, вы захотите сделать это с помощью отдельного скрипта. Тот, который определяет, когда копировать файл, и делает это независимо от этого скрипта. Я не уверен, как вы это сделаете на windows, но первая идея, которая приходит на ум, - это al oop, который отслеживает временную метку в файле и когда он изменяется, надеюсь, это сигнализирует о завершении записи и делает скопируйте в тот момент. Или

  3. Поймать исключение, зафиксировать то, что у вас получилось, а затем начать заново.

        file = open('C:/Users/LV98/Desktop/Database Test/FMSExport.csv')
        reader = csv.reader(file)
        lines = len(list(reader))

        try:
             # all that inner stuff
        except mysql.connector.errors.ProgrammingError as ex:
            # oops, we didnt finish
        finally:
            # capture what we have
            mysqlConnection.commit()
            mySQLcursor1.close()

        continue

По звуку возможно, вы никогда не обработаете весь файл?

Уместится ли в памяти весь файл? Возможно, вместо того, чтобы пытаться одновременно читать из файла и записывать в базу данных, вы загружаете весь файл в память, а затем генерируете и фиксируете свой SQL в БД. Таким образом, если вы загрузите все это в память до того, как оно снова начнет меняться, он может начать переписывать файл, и вам все равно, потому что у вас есть снимок предыдущей версии в памяти для работы.
0 голосов
/ 19 мая 2020

Заменяет ли файл какой-то внешний процесс?

Вместо прямой загрузки из файла сначала переименуйте файл. Затем LOAD из переименованного файла. Это должно почти всегда избегать того, чтобы на вас наступили.

Если проблема связана с чем-то еще, пожалуйста, объясните.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...