Вставка больших текстовых данных в postgres с помощью python

#python #postgresql #psycopg2

#python #postgresql #psycopg2

Вопрос:

Я пытаюсь выполнить массовую вставку длинных XML-строк в виде текста в базу данных postgresql 9.1. Я использую Python 3.2 и pyscopg2. Я заключаю строку xml в $$ и использую именованную переменную в строке запроса. Например:

 query = "insert into cms_object_metadata (cms_object_id, cms_object_metadata_data, cms_object_metadata_type_id, 
         cms_object_metadata_status_id) values ((select id from cms_objects where cms_object_ident = %(objIdent)s), 
         $$%(objMetaString)s$, (select id from cms_object_metadata_types where cms_object_metadata_type_name = 'PDAT'), 
         (select id from cms_object_metadata_status where cms_object_metadata_status_name = 'active'))"
 

Затем я создаю объект словаря следующим образом:

 dataDict = {'objIdent':objIdent, 'objMetaString':objMetaString}
 

передача значений objIdent и objMetaString. Я выполняю вставку с помощью следующего кода:

 dbCursor.execute(query, dataDict)
 

Когда он вставляет значение objMetaString в базу данных, он заключает строку в одинарные кавычки. Если я добавляю значения в строку запроса и выполняю вставку без именованной переменной, это не так. Например:

 query = "insert into cms_object_metadata (cms_object_id, cms_object_metadata_data, cms_object_metadata_type_id, 
         cms_object_metadata_status_id) values ((select id from cms_objects where cms_object_ident = %s), 
         $$%s$, (select id from cms_object_metadata_types where cms_object_metadata_type_name = 'PDAT'), 
         (select id from cms_object_metadata_status where cms_object_metadata_status_name = 'active'))" % (objIdent, objMetaString)
 

и вставка:

 dbCursor.execute(query)
 

Мой вопрос заключается в том, как выполнить массовую вставку больших текстовых данных, используя именованные переменные и $$. Я действительно не хочу обрабатывать эту строку до или после, если это возможно, поскольку они могут быть большими и содержать неизвестное количество одинарных кавычек или других символов, которые необходимо будет разделить.
Я прочитал следующую документацию и искал ответ в stackoverflow, но не нашел решения:

Комментарии:

1. Почему вы так уверены, что ваши большие текстовые данные не содержат $$ , чтобы вам не приходилось их избегать?

2. Если я правильно понял, прочитав это, вам не нужно беспокоиться о каких-либо $ в строке. Цитата из документов Postgresql: 4.1.2.4. Строковые константы, заключенные в долларовые кавычки — Обратите внимание, что внутри строки, заключенной в долларовые кавычки, одинарные кавычки можно использовать без необходимости экранирования. Действительно, никакие символы внутри строки, заключенной в долларовые кавычки, никогда не экранируются: содержимое строки всегда записывается буквально. Обратная косая черта не является специальной, как и знаки доллара, если только они не являются частью последовательности, соответствующей открывающему тегу.

3. Вам следует беспокоиться. Смотрите последнее предложение того, что вы процитировали.

4. Вы правы, но я все еще задаюсь вопросом, как лучше всего справиться с этим, нужно ли мне анализировать полную строку и экранировать, где это необходимо, и не использовать синтаксис $$. Я не против проверить открывающий тег для них, но надеялся избежать синтаксического анализа всего текста в каждой строке. В нашем конкретном случае мы создаем xml и вставляем значения, поэтому у меня есть некоторый контроль над xml, но не над значениями. Должен быть стандартный способ сделать это???

5. Стандартный способ сделать это — позволить драйверу обработать это, как в вашем первом примере кода.

Ответ №1:

Подведение итогов темы комментариев. Сделайте это:

 query = "insert into cms_object_metadata (cms_object_id, cms_object_metadata_data, cms_object_metadata_type_id, 
         cms_object_metadata_status_id) values ((select id from cms_objects where cms_object_ident = %(objIdent)s), 
         %(objMetaString)s, (select id from cms_object_metadata_types where cms_object_metadata_type_name = 'PDAT'), 
         (select id from cms_object_metadata_status where cms_object_metadata_status_name = 'active'))"

dataDict = {'objIdent':objIdent, 'objMetaString':objMetaString}

dbCursor.execute(query, dataDict)
 

Не заключайте %(objMetaString)s заполнитель в кавычки в своем запросе. При необходимости указать значение — задача драйвера.