Nano Hash - криптовалюты, майнинг, программирование

Python Sqlite3: INSERT INTO table VALUE (сюда идет словарь)

Я хотел бы использовать словарь для вставки значений в таблицу, как мне это сделать?

import sqlite3

db = sqlite3.connect('local.db')
cur = db.cursor()

cur.execute('DROP TABLE IF EXISTS Media')

cur.execute('''CREATE TABLE IF NOT EXISTS Media(
                id INTEGER PRIMARY KEY, title TEXT, 
                type TEXT,  genre TEXT,
                onchapter INTEGER,  chapters INTEGER,
                status TEXT
                )''')


values = {'title':'jack', 'type':None, 'genre':'Action', 'onchapter':None,'chapters':6,'status':'Ongoing'}

#What would I Replace x with to allow a 
#dictionary to connect to the values? 
cur.execute('INSERT INTO Media VALUES (NULL, x)'), values)
cur.execute('SELECT * FROM Media')

meida = cur.fetchone()

print meida

  • Вот вопрос: зачем вам это? Чего вы пытаетесь достичь и почему, по вашему мнению, правильно синхронизировать две совершенно разные вещи (таблицу SQL и набор ключей dict)? 01.01.2013
  • Не знаю, что хотел первоначальный автор, но я нашел вопрос, потому что я генерирую create table из структуры файла XML, затем, когда я перехожу к insert строкам, у меня есть атрибуты и vals в словаре и Я знаю, что они будут в базе данных, но они никогда не бывают статичными. 27.08.2014
  • @eichin Я знаю, что это немного поздно, но ... Если вы просто предварительно загружаете базу данных из XML для более статического использования позже, я бы, вероятно, создал скрипт загрузки вместо набора вставок; если вы на самом деле все время обращаетесь к базе данных с динамическими столбцами, вам следует серьезно рассмотреть другой тип хранилища, чем реляционная база данных SQL. То, что вы делаете, может быть лучшим в вашем случае, но обычно это не так, поэтому SQL усложняет задачу. 09.03.2016

Ответы:


1

Если вы пытаетесь использовать dict для указания как имен столбцов, так и значений, вы не можете этого сделать, по крайней мере, напрямую.

Это действительно присуще SQL. Если вы не укажете список имен столбцов, вы должны указать их в порядке CREATE TABLE, чего нельзя сделать с dict, потому что dict не имеет порядка. Конечно, если вы действительно этого хотите, вы можете использовать collections.OrderedDict, убедиться, что они в правильном порядке, а затем просто передать values.values(). Но в таком случае, почему бы сразу не поставить list (или tuple)? Если вы абсолютно уверены, что получили все значения в правильном порядке, и хотите обращаться к ним по порядку, а не по имени, у вас есть list, а не dict.

И нет способа связать имена столбцов (или имена таблиц и т. д.) в SQL, только значения.

Вы можете, конечно, сгенерировать оператор SQL динамически. Например:

columns = ', '.join(values.keys())
placeholders = ', '.join('?' * len(values))
sql = 'INSERT INTO Media ({}) VALUES ({})'.format(columns, placeholders)
values = [int(x) if isinstance(x, bool) else x for x in values.values()]
cur.execute(sql, values)

Однако это почти всегда плохая идея. На самом деле это ненамного лучше, чем генерация и execинг динамического кода Python. И вы только что потеряли все преимущества использования заполнителей в первую очередь — в первую очередь защиту от атак с внедрением SQL, но также и менее важные вещи, такие как более быстрая компиляция, лучшее кэширование и т. д. в механизме БД.

Вероятно, лучше сделать шаг назад и посмотреть на эту проблему с более высокого уровня. Например, может быть, вам нужен не статический список свойств, а таблица "имя-значение" MediaProperties? Или, в качестве альтернативы, может быть, вам нужно какое-то хранилище на основе документов (будь то мощная система nosql или просто набор объектов JSON или YAML, хранящихся в shelve)?


Альтернативный вариант с использованием именованных заполнителей:

columns = ', '.join(my_dict.keys())
placeholders = ':'+', :'.join(my_dict.keys())
query = 'INSERT INTO my_table (%s) VALUES (%s)' % (columns, placeholders)
print query
cur.execute(query, my_dict)
con.commit()
01.01.2013
  • @oche: не тестировалось, но код кажется неправильным. Вставка ключей в таблицу дважды (для заполнителя) выглядит как небольшая ошибка. Нет, вызов execute заменяет каждый именованный заполнитель поиском его имени в качестве ключа в my_dict. Поэтому однозначно должно быть keys, а не values. Представьте, что my_dict = {'spam': 'eggs'}. Если вы поместите заполнитель :eggs в оператор SQL, его не будет в my_dict; вам нужно :spam. 21.05.2015
  • Заполнители автоматически выполняют правильное экранирование, тогда как если вы создаете запрос самостоятельно, вам необходимо закодировать логику экранирования специального символа. 07.10.2015
  • Заполнители не делают правильного экранирования, даже автоматически. Они просто не экранируются, потому что не вставляются текстом в инструкцию SQL. 17.02.2016
  • @ JürgenA.Erhard Технически, под прикрытием, некоторые библиотеки SQL действительно обрабатывают заполнители, просто экранируя их в строке… Но пользователям не обязательно об этом знать; каждая библиотека SQL лучше всего справляется с заполнителями для своего бэкэнда и делает это правильно, поэтому +1 к вашему комментарию. 09.03.2016
  • Работает как шарм! ты 10.08.2017
  • В нижней части ответа нет пользовательских заполнителей, где указано, что это так. Ознакомьтесь с docs.python.org/2/library/sqlite3.html. 28.09.2017
  • because a dict has no order... начиная с Python 3.7 в словаре теперь есть порядок. https://mail.python.org/pipermail/python-dev/2017-December/151283.html 31.12.2019

  • 2

    Есть решение для использования словарей. Во-первых, оператор SQL

    INSERT INTO Media VALUES (NULL, 'x');
    

    не будет работать, так как предполагается, что вы имеете в виду все столбцы в том порядке, в котором они определены в операторе CREATE TABLE, как заявил abarnert. (См. ВСТАВКА SQLite.)

    После того, как вы исправили это, указав столбцы, вы можете использовать именованные заполнители для вставки данных. Преимущество этого в том, что он безопасно избегает ключевых символов, так что вам не о чем беспокоиться. Из Python sqlite-documentation:

    values = {
        'title':'jack', 'type':None, 'genre':'Action', 
        'onchapter':None,'chapters':6,'status':'Ongoing'
    }
    cur.execute(
        'INSERT INTO Media (id, title, type, onchapter, chapters, status)
         VALUES (:id, :title, :type, :onchapter, :chapters, :status);', 
        values
    )
    
    22.05.2013
  • Эй, я сделал правку, но потом обнаружил еще одну ошибку, и я не могу изменить достаточно, чтобы сделать еще одну, ха-ха. В конце вашего утверждения у вас есть );)', которое execute() будет читать, когда вы пытаетесь сделать несколько утверждений. Удалите лишние ) и все будет хорошо. :) 20.11.2018

  • 3

    Вы можете использовать именованные параметры:

    cur.execute('INSERT INTO Media VALUES (NULL, :title, :type, :genre, :onchapter, :chapters, :status)', values)
    

    Это по-прежнему зависит от порядка столбцов в операторе INSERT (эти : используются только как ключи в values dict), но, по крайней мере, это избавляет от необходимости упорядочивать значения на стороне python, плюс вы можете иметь другие вещи в values, которые здесь игнорируются; если вы разделяете то, что находится в словаре, чтобы сохранить его в нескольких таблицах, это может быть полезно.

    Если вы по-прежнему хотите избежать дублирования имен, вы можете извлечь их из объекта результата sqlite3.Row или из cur.description после выполнения фиктивного запроса; может быть разумнее держать их в форме питона рядом с тем местом, где вы делаете CREATE TABLE.

    15.01.2015

    4

    Вот более общий способ с преимуществом побега:

    # One way. If keys can be corrupted don't use.
    sql = 'INSERT INTO demo ({}) VALUES ({})'.format(
                ','.join(my_dict.keys()),
                ','.join(['?']*len(my_dict)))
    
    # Another, better way. Hardcoded w/ your keys.
    sql = 'INSERT INTO demo ({}) VALUES ({})'.format(
                ','.join(my_keys),
                ','.join(['?']*len(my_dict)))
    
    cur.execute(sql, tuple(my_dict.values()))
    
    06.06.2019

    5
    key_lst = ('status', 'title', 'chapters', 'onchapter', 'genre', 'type')
    cur.execute('INSERT INTO Media (status,title,chapters,onchapter,genre,type) VALUES ' + 
                '(?,?,?,?,?,?);)',tuple(values[k] for k in key_lst))
    

    Убегайте правильно.

    Вероятно, вам также понадобится вызов commit где-то там.

    01.01.2013
  • Почему бы не использовать key_lst для указания порядка столбцов вместо повторного ввода? cur.execute('INSERT INTO Media ({}) VALUES ();'.format(','.join(key_lst), ','.join(['?'] * len(key_lst))), tuple(values[k] for k in key_lst)) 22.05.2013
  • @MrGumble, потому что вы все еще позволяете, возможно, предоставленным пользователем данным входить в инструкцию sql, не экранируя ее. И я думаю, что вам не хватает {} в операторе формата. Вы должны включить это предложение в свой ответ, если оно вам нравится. 22.05.2013

  • 6

    Очень поздно к этому, но решил добавить свой собственный ответ. Не эксперт, но то, что я нашел, что работает.

    Есть проблемы с сохранением порядка при использовании словаря, о которых заявили другие пользователи, но вы можете сделать следующее:

    # We're going to use a list of dictionaries, since that's what I'm having to use in my problem
    input_list = [{'a' : 1 , 'b' : 2 , 'c' : 3} , {'a' : 14 , 'b' : '' , 'c' : 43}]
    for i in input_list:
        # I recommend putting this inside a function, this way if this 
        # Evaluates to None at the end of the loop, you can exit without doing an insert
        if i :
            input_dict = i 
        else:
            input_dict = None
            continue
    # I am noting here that in my case, I know all columns will exist.
    # If you're not sure, you'll have to get all possible columns first.
    
    keylist = list(input_dict.keys())
    vallist = list(input_dict.values())
    
    query = 'INSERT INTO example (' +','.join( ['[' + i + ']' for i in keylist]) + ') VALUES (' + ','.join(['?' for i in vallist]) + ')'
    
    items_to_insert = list(tuple(x.get(i , '') for i in keylist) for x in input_list)
    # Making sure to preserve insert order. 
    
    conn = sqlite3.connect(':memory:')
    cur = conn.cursor()
    cur.executemany(query , items_to_insert)
    conn.commit()
    
    10.09.2019

    7
    dictionary = {'id':123, 'name': 'Abc', 'address':'xyz'}    
    query = "insert into table_name " + str(tuple(dictionary.keys())) + " values" + str(tuple(dictionary.values())) + ";"
    cursor.execute(query)
    

    запрос становится

    insert into table_name ('id', 'name', 'address') values(123, 'Abc', 'xyz');
    
    06.05.2020

    8

    У меня была аналогичная проблема, поэтому я сначала создал строку, а затем передал эту строку для выполнения команды. Выполнение занимает больше времени, но отображение было идеальным для меня. Просто работа вокруг:

    create_string = "INSERT INTO datapath_rtg( Sr_no"
    for key in record_tab:
        create_string = create_string+ " ," + str(key)
    create_string = create_string+ ") VALUES("+ str(Sr_no) 
    for key in record_tab:
        create_string = create_string+ " ," + str(record_tab[key])
    create_string = create_string + ")"
    cursor.execute(create_string)
    

    Сделав вышеописанное, я убедился, что если мой словарь (record_tab) не содержит определенного поля, то скрипт не выдаст ошибку, и можно будет выполнить правильное сопоставление, поэтому я в первую очередь использовал словарь.

    18.01.2017

    9

    У меня была аналогичная проблема, и в итоге получилось что-то не совсем отличное от следующего (Примечание. Это код OP с измененными битами, чтобы он работал так, как они просили) -

    import sqlite3
    db = sqlite3.connect('local.db')
    cur = db.cursor()
    
    cur.execute('DROP TABLE IF EXISTS Media')
    
    cur.execute('''CREATE TABLE IF NOT EXISTS Media(
                    id INTEGER PRIMARY KEY, title TEXT, 
                    type TEXT,  genre TEXT,
                    onchapter INTEGER,  chapters INTEGER,
                    status TEXT
                    )''')
    
    
    values = {'title':'jack', 'type':None, 'genre':'Action',     'onchapter':None,'chapters':6,'status':'Ongoing'}
    
    #What would I Replace x with to allow a 
    #dictionary to connect to the values? 
    #cur.execute('INSERT INTO Media VALUES (NULL, x)'), values)
    # Added code.
    cur.execute('SELECT * FROM Media')
    colnames = cur.description
    list = [row[0] for row in cur.description]
    new_list = [values[i] for i in list if i in values.keys()]
    sql = "INSERT INTO Media VALUES ( NULL, "
    qmarks = ', '.join('?' * len(values))
    sql += qmarks + ")"
    cur.execute(sql, new_list)
    #db.commit() #<-Might be important.
    cur.execute('SELECT * FROM Media')
    media = cur.fetchone()
    print (media)
    
    19.02.2018
    Новые материалы

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

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..