Pass many list parameter to a query in Python - python

I have three lists:
countries=['AUSTRALIA', 'FRANCE', 'ITALY']
segments=['little','medium','big','huge']
costumers = ['ERIK','FRANK','BOB', 'JANE']
I have to write something like this:
cursor.execute("SELECT COUNTRY, SEGMENT, CUSTOMER, VALUE
WHERE COUNTRY IN ?, SEGMENT IN ?, VALUE IN ?, (countries, segments, costumers))
Any idea? The three lists may vary in terms of number of components for each list.
Thanks in advance!

This can be solved in the following way:
cursor.execute("SELECT country, segment, customer, value" +
"WHERE country IN %(1)s, SEGMENT IN %(2)s, VALUE IN %(3)s",
{"1": tuple(countries), "2": tuple(segments), "3": tuple(customers)})
This ensures you still have the protection from SQL injections you had earlier. It also doesn't fail on strings.

You can do something like this:
countries=['AUSTRALIA', 'FRANCE', 'ITALY']
segments=['little','medium','big','huge']
costumers = ['ERIK','FRANK','BOB', 'JANE']
query = ("SELECT COUNTRY, SEGMENT, CUSTOMER, VALUE "
" WHERE COUNTRY IN ('{}') "
" AND SEGMENT IN ('{}') "
" AND VALUE IN ('{}')").format(countries, segments, costumers)
cursor.execute(query)

This might look like more code than the other solutions which directly pass in values using string formatting, but it is much safer. Read up on SQL injection to understand why.
The difficulty in passing values as parameters (much safer than string formatting) is that the query has to look something like this before you can pass in parameters (the number of ?s varies depending on number of parameters to be passed in):
"SELECT COUNTRY, SEGMENT, CUSTOMER, VALUE FROM SOME_TABLE WHERE COUNTRY IN (?, ?, ?) AND SEGMENT IN (?, ?, ?) AND VALUE IN (?, ?, ?)"
So you need to use string formatting to pass the appropriate number of ? placeholders:
countries=['AUSTRALIA', 'FRANCE', 'ITALY']
segments=['little','medium','big','huge']
customers = ['ERIK','FRANK','BOB', 'JANE']
country_placeholders = ','.join('?' for i in range(len(countries)))
segment_placeholders = ','.join('?' for i in range(len(segments)))
customer_placeholders = ','.join('?' for i in range(len(customers)))
query = """
SELECT COUNTRY, SEGMENT, CUSTOMER, VALUE FROM SOME_TABLE WHERE COUNTRY IN ({}) AND SEGMENT IN ({}) AND VALUE IN ({})
""".format(country_placeholders, segment_placeholders, customer_placeholders)
This gives you the following query template:
"SELECT COUNTRY, SEGMENT, CUSTOMER, VALUE FROM SOME_TABLE WHERE COUNTRY IN (?,?,?) AND SEGMENT IN (?,?,?,?) AND VALUE IN (?,?,?,?)"
Now you just need to execute and pass your parameters:
params = tuple(countries + segments + customers)
cursor.execute(query, params)

Related

ValueError: operation parameter must be str? Would end up with three parameters

I am trying to run this insert function that is apart of a bigger code but I keep getting "ValueError: operation parameter must be str." I have seen this question before and I know to avoid tuples, however, if I separate the arguments I end up having three parameters:
def insert(self, table, params):
keys = ', '.join(params.keys())
values = params.values()
query = "INSERT INTO songs (%s) VALUES (?, ?);" ,
keys
self.cur.execute(query , values)
self.conn.commit()
return self.cur.lastrowid
This line:
query = "INSERT INTO songs (%s) VALUES (?, ?);" ,
keys
sets query to a tuple, but it needs to be a string. You should use a formatting method to substitute keys into the string.
query = f"INSERT INTO songs ({keys}) VALUES (?, ?);"

python sqlite3 parameterization - insert throws no such column error

Insert in columns with parameterized query throws no such column error
First (working) example:
# unit test input
name = "issue_number_1"
text = "issue_text"
rating_sum = 0
if name:
# check if issue is already in db
with self.conn: # this should release the connection when finished
test = cursor.execute("SELECT name, text FROM issue WHERE name = ?", (name,))
data = test.fetchall()
print(data)
this is working and prints:
[('issue_number_1', 'issue_text')]
Second (non working) example:
# unit test input
name = "issue_number_2"
text = "issue_text"
rating_sum = 0
if name:
with self.conn:
sql_string = "INSERT INTO issue (name, text, rating_sum) VALUES (name = ?, text = ?, rating_sum = ?)"
cursor.execute(sql_string, (name, text, rating_sum,))
throws this error:
cursor.execute(sql_string, (name, text, rating_sum,))
sqlite3.OperationalError: no such column: name
the column name exists, the first example proofed that
the name: "issue_number_2" does not exist in the DB
the second example fails exactly same with only name to insert (only one parameter)
i had no problems inserting with string concatenation so the problem should be in my second example code somewhere
You need to add single quote.for example:
"INSERT INTO table (field) VALUES ('$1')"
add just values in second () and add single quote around string values.
After a lot of experiments i was a little bit confused....
This is the right syntax:
sql_string = "INSERT INTO issue (name, text, rating_sum) VALUES (?, ?, ?)"
cursor.execute(sql_string, (name, text, rating_sum,))
The statement:
INSERT INTO .... VALUES ....
is an SQL statement and the correct syntax is:
INSERT INTO tablename (col1, col2, ...) VALUES (expr1, expr2, ...)
where col1, col2, ... are columns of the table tablename and expr1, expr2, ... are expressions or literals that are evaluated and assigned to each of the columns col1, col2, ... respectively.
So the syntax that you use is not valid SQL syntax.
The assignment of the values is not performed inside VALUES(...).
The correct syntax to use in Python would be:
INSERT INTO issue (name, text, rating_sum) VALUES (?, ?, ?)

Python sqlite3 - operationalerror near "2017"

I'm new to programming. I have dictionary called record, that receives various inputs like 'Color', 'Type' 'quantity',etc. Now I tried to add a Date column then insert into sqlite table running through the 'if loop' with the code below. But I get an "Operational error near 2017", ie near the date.
Can anyone help please? Thanks in advance
Date = str(datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d'))
record['Date'] = Date
column = [record['Color'], Date]
values = [record['quantity'], record['Date']]
column = ','.join(column)
if record['Type'] == 'T-Shirts' and record['Style'] == 'Soft':
stment = ("INSERT INTO xtrasmall (%s) values(?)" %column)
c.execute(stment, values)
conn.commit()
Updated
You can simplify the code as follows:
from datetime import datetime
date = datetime.now().date()
sql = "INSERT INTO xtrasmall (%s, Date) values (?, ?)" % record['Color']
c.execute(sql, (record['quantity'], date))
This substitutes the value of the selected color directly into the column names in the query string. Then the query is executed passing the quantity and date string as arguments. The date should automatically be converted to a string, but you could convert with str() if desired.
This does assume that the other colour columns have a default value (presumably 0), or permit null values.
Original answer
Because you are constructing the query with string interpolation (i.e. substituting %s for a string) your statement becomes something like this:
INSERT INTO xtrasmall (Red,2017-10-06) values(?)
which is not valid because 2017-10-06 is not a valid column name. Print out stment before executing it to see.
If you know what the column names are just specify them in the query:
values = ['Red', 2, Date]
c.execute("INSERT INTO xtrasmall (color, quantity, date) values (?, ?, ?)", values)
conn.commit()
You need to use a ? for each column that you are inserting.
It looks like you want to insert the dictionary using its keys and values. This can be done like this:
record = {'date':'2017-10-06', 'color': 'Red', 'quantity': 2}
columns = ','.join(record.keys())
placeholders = ','.join('?' * len(record.values()))
sql = 'INSERT INTO xtrasmall ({}) VALUES ({})'.format(columns, placeholders)
c.execute(sql, record.values())
This code will generate the parameterised SQL statement:
INSERT INTO xtrasmall (date,color,quantity) VALUES (?,?,?)
and then execute it using the dictionary's values as the parameters.

retrieving data from one table and putting into another PYTHON SQL

Trying to take a piece of data from at table in the database and inserting it into another table:
Fetching the order total and assigning it to variable:
cursor.execute('''SELECT Price FROM Tracks WHERE TrackID = ?''', (trackChoice,))
ordertotal = str(cursor.fetchall())
Putting it into table:
cursor.execute('''INSERT INTO Orders(OrderID, Date, OrderTotal, CustomerID, TrackID) VALUES(?, ?, ?, ?, ?)''', (orderID, date,
ordertotal, customerID, trackChoice))
Error:
sqlite3.InterfaceError: Error binding parameter 2 - probably unsupported type.
With cursor.fetchall() you get all the rows in 'Tracks'. So it will have an ID and probably other informations as well. f.E. something like this: (1, 'William', 'Shakespeare', 'm', None, '1961-10-25'). What is 'ordertotal'? I guess it will be a number? If yes, and you are using sqlite3 you could use row_factory. See the answere here for more information: Get a list of field values from Python's sqlite3, not tuples representing rows
Why not just do:
cursor.execute("""
INSERT INTO Orders(name, Date, name, name, name)
VALUES(?, strftime('now'), ?, ?, ?)""",
(value, value, value, value);
That is, use the current time in the database.
(I assume that name is really four different columns or you should get another error.)

Inserting tuple's elements to database

I have a tuple that i wanna store its elements, I'm trying to insert it as following and it gives the following error, what am i doing wrong ? records_to_be_inserted is the tuple that has 8 elements.
with self.connection:
cur = self.connection.cursor()
cur.executemany("INSERT INTO rehberim(names, phone, mobile, email, \
photo, address, note, date) VALUES(?, ?, ?, ?, ?, ?, ?, ?)", self.records_to_be_inserTed)
Traceback (most recent call last):
File "/home/tayfun/workspace/personal_guide/modules/mainwindow.py", line 57, in save_records
photo, address, note, date) VALUES(?, ?, ?, ?, ?, ?, ?, ?)", self.records_to_be_inserTed)
sqlite3.ProgrammingError: Incorrect number of bindings supplied. The current statement uses 8, and there are 0 supplied.
Note that the executemany is for inserting multiple rows, e.g.,
import sqlite3
""" the table structure is:
create table tab
a char(1),
b char(2),
c char(3)
)
"""
conn = sqlite3.connect('C:\\test.db')
stmt = "insert into tab (a, b, c) values (?, ?, ?)"
cur = conn.cursor()
## many rows
vals = [('1','2','3'), ('2','3','4'), ('3','4','5')]
cur.executemany(stmt, vals)
cur.close()
This will result in three rows in the database. If it is because you have multiple values in one query, you need to format it!
Edit: Added formatting with dictionaries
By using the following approach you do not need to consider the order of the values in the format call because the key in the dictionary is mapping the value into the {key_word} placeholder.
values = {'a' : 'value_a',
'b' : 'value_b'}
stmt = "insert into tab (col_a, col_b) values ({a}, {b})".format(**values)
The query must have all the data ready to be inserted.
You are calling a function in the query, which i guess you want that provides the data but that wont work.
You need to pass all the data in variables or locate them in the tuple index (like: tuple_name[1], tuple_name[4], etc.)
Example:
myTuple = ['a','b','c','d','e','f','g']
cur.executemany("INSERT INTO rehberim(names, phone, mobile, email, \
photo, address, note, date) VALUES({0}, {1}, {2}, {3}, {4}, {5}, {6}" .format (myTuple[1], myTuple[2], myTuple[3], myTuple[4], myTuple[5], myTuple[6], myTuple[7])

Categories