Имя переменной таблицы в sqlite

Вопрос: возможно ли использовать переменную в качестве имени таблицы без необходимости использовать для этого строковые конструкторы?


Информация:

Я сейчас работаю над проектом, который каталогизирует данные моей звездной симуляции. Для этого я загружаю все данные в базу данных sqlite. Это работает довольно хорошо, но я решил добавить гораздо больше гибкости, эффективности и удобства использования для моей базы данных. Я планировал позже добавить планетоиды к симуляции и хотел иметь таблицу для каждой звезды. Таким образом, мне не пришлось бы запрашивать таблицу с 20-метровыми планетоидами для 1-4k в каждой солнечной системе.

Мне сказали, что использование строковых конструкторов плохо, потому что это делает меня уязвимым для атаки SQL-инъекцией. Хотя это не имеет большого значения, так как я единственный человек, имеющий доступ к этим базам данных, я хотел бы следовать передовым методам. И так же, если я делаю проект с похожей ситуацией, когда он открыт для публики, я знаю, что делать.

В настоящее время я делаю это:

cursor.execute("CREATE TABLE StarFrame"+self.name+" (etc etc)")

Это работает, но я хотел бы сделать что-то вроде:

cursor.execute("CREATE TABLE StarFrame(?) (etc etc)",self.name)

хотя я понимаю, что это, вероятно, было бы невозможно. хотя я бы согласился на что-то вроде

cursor.execute("CREATE TABLE (?) (etc etc)",self.name)

Если это вообще невозможно, я приму этот ответ, но если кто-нибудь знает способ сделать это, скажите.:)

Я пишу в Python.

10 ответов

Решение

К сожалению, таблицы не могут быть целью замены параметров (я не нашел никакого определенного источника, но я видел это на нескольких веб-форумах).

Если вы беспокоитесь о внедрении (вероятно, так и должно быть), вы можете написать функцию, которая очищает строку перед ее передачей. Поскольку вы ищете только имя таблицы, вы должны быть в безопасности, просто принимая буквенно-цифровые символы, удаляя все знаки препинания, такие как )(][;, и пробелы. В основном, просто держать A-Z a-z 0-9,

def scrub(table_name):
    return ''.join( chr for chr in table_name if chr.isalnum() )

scrub('); drop tables --')  # returns 'droptables'

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

Он сказал следующее, и это работает. Это все цитируется из Mhawke:

Вы не можете использовать подстановку параметров для имени таблицы. Вам нужно добавить имя таблицы в строку запроса самостоятельно. Что-то вроде этого:

query = 'SELECT * FROM {}'.format(table)
c.execute(query)

Следует помнить об источнике значения для имени таблицы. Если это происходит из ненадежного источника, например, от пользователя, вам необходимо проверить имя таблицы, чтобы избежать потенциальных атак SQL-инъекций. Одним из способов может быть создание параметризованного запроса, который ищет имя таблицы из каталога БД:

import sqlite3

def exists_table(db, name):
    query = "SELECT 1 FROM sqlite_master WHERE type='table' and name = ?"
    return db.execute(query, (name,)).fetchone() is not None

Я бы не разделил данные на несколько таблиц. Если вы создадите индекс для звездного столбца, у вас не возникнет проблем с эффективным доступом к данным.

Попробуйте с форматированием строки:

sql_cmd = '''CREATE TABLE {}(id, column1, column2, column2)'''.format(
            'table_name')
db.execute(sql_cmd)

замещать 'table_name' с твоим желанием.

Чтобы избежать жесткого кодирования имен таблиц, я использовал:

table = "sometable"
c = conn.cursor()

c.execute('''CREATE TABLE IF NOT EXISTS {} (
                importantdate DATE,
                somename VARCHAR,
                )'''.format(table))

c.execute('''INSERT INTO {} VALUES (?, ?)'''.format(table),
                  (datetime.strftime(datetime.today(), "%Y-%m-%d"),
                   myname))

А что насчет f-Strings, гораздо более читабельно.

      table = "myTableName"
condition = "ID = 5"
sql = f'''SELECT * FROM {table} WHERE {condition}'''

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

import sys
import sqlite3
def delim(s):
  delims="\"'`"
  use_delim = []
  for d in delims:
   if d not in s:
    use_delim.append(d)
  return use_delim

db_name = "some.db"
db = sqlite3.connect(db_name)
mycursor = db.cursor()
table = 'so""m ][ `etable'
delimiters = delim(table)
if len(delimiters) < 1:
    print "The name of the database will not allow this!"
    sys.exit()
use_delimiter = delimiters[0]
print "Using delimiter ", use_delimiter
mycursor.execute('SELECT name FROM sqlite_master where (name = ?)', [table])
row = mycursor.fetchall()
valid_table = False
if row:
    print (table,"table name verified")
    valid_table = True
else:
    print (table,"Table name not in database", db_name)

if valid_table:
    try:
        mycursor.execute('insert into ' +use_delimiter+ table +use_delimiter+ ' (my_data,my_column_name) values (?,?) ',(1,"Name"));
        db.commit()
    except Exception as e:
        print "Error:", str(e)
    try:
        mycursor.execute('UPDATE ' +use_delimiter+ table +use_delimiter+ ' set my_column_name = ? where my_data = ?', ["ReNamed",1])
        db.commit()
    except Exception as e:
        print "Error:", str(e)
db.close()

Вы можете использовать что-то вроде этого conn = sqlite3.connect() createTable = '''CREATE TABLE %s (# );''' %dateNow) conn.execute(createTable)

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

createTable = '''CREATE TABLE%s (#);' ''%dateNow) означает, что вы создаете таблицу с переменной dateNow, которая в соответствии с вашим языком программирования, вы можете определить dateNow как переменную для извлечения текущей даты из вашего кода язык.

Вы можете сохранить свой запрос в файле .sql или txt и использовать метод open(). Replace() для использования переменных в любой части вашего запроса. Давний читатель, но первый плакат, поэтому прошу прощения, если что-то здесь не так.

Вы можете передать строку как команду SQL:

import sqlite3
conn = sqlite3.connect('db.db')
c = conn.cursor()
tablename, field_data = 'some_table','some_data'
query = 'SELECT * FROM '+tablename+' WHERE column1=\"'+field_data+"\""
c.execute(query)
Другие вопросы по тегам