Passing a column name in a SELECT statement in Python - python

if count == 1:
cursor.execute("SELECT * FROM PacketManager WHERE ? = ?", filters[0], parameters[0])
all_rows = cursor.fetchall()
elif count == 2:
cursor.execute("SELECT * FROM PacketManager WHERE ? = ? AND ? = ?", filters[0], parameters[0], filters[1], parameters[1])
all_rows = cursor.fetchall()
elif count == 3 :
cursor.execute("SELECT * FROM PacketManager WHERE ? = ? AND ? = ? AND ? = ?", filters[0], parameters[0], filters[1], parameters[1], filters[2], parameters[2])
all_rows = cursor.fetchall()
This is a code snippet in my program. What I'm planning to do is pass the column name and the parameter in the query.
The filters array contains the columnnames, the parameter array contains the parameters. The count is the number of filters set by the user. The filters and paramters array are already ready and have no problem. I just need to pass it to the query for it to execute. This give me an error of "TypeError: function takes at most 2 arguments"

You cannot use SQL parameters to interpolate column names. You'll have to use classic string formatting for those parts. That's the point of SQL parameters; they quote values so they cannot possibly be interpreted as SQL statements or object names.
The following, using string formatting for the column name works, but be 100% certain that the filters[0] value doesn't come from user input:
cursor.execute("SELECT * FROM PacketManager WHERE {} = ?".format(filters[0]), (parameters[0],))
You probably want to validate the column name against a set of permissible column names, to ensure no injection can take place.

You can only set parameters using ?, not table or column names.
You could build a dict with predefined queries.
queries = {
"foo": "SELECT * FROM PacketManager WHERE foo = ?",
"bar": "SELECT * FROM PacketManager WHERE bar = ?",
"foo_bar": "SELECT * FROM PacketManager WHERE foo = ? AND bar = ?",
}
# count == 1
cursor.execute(queries[filters[0], parameters[0])
# count == 2
cursor.execute(queries[filters[0] + "_" + queries[filters[1], parameters[0])
This approach will make you save from SQL injection in filters[0].

Related

How to the store a column from a SQL request into a variable?

I want to put the result of each column of the result of my request and store them into separate variables, so I can exploit its results.
I precise this is with a SELECt * and not separate requests.
So, If I do for example:
with connection.cursor() as cursor:
# Read a single record
sql = 'SELECT * FROM table'
cursor.execute(sql)
result = cursor.fetchall()
print(result)
I want to do :
a = [results from column1]
b = [results from column2]
The results should be turned into a row and not be left as a column, to make it a dictionary.
It's probably very simple but I'm new with Python / SQL, thank you.

Alter query according to user selection in sqlite python

I have a sqlite database named StudentDB which has 3 columns Roll number, Name, Marks. Now I want to fetch only the columns that user selects in the IDE. User can select one column or two or all the three. How can I alter the query accordingly using Python?
I tried:
import sqlite3
sel={"Roll Number":12}
query = 'select * from StudentDB Where({seq})'.format(seq=','.join(['?']*len(sel))),[i for k,i in sel.items()]
con = sqlite3.connect(database)
cur = con.cursor()
cur.execute(query)
all_data = cur.fetchall()
all_data
I am getting:
operation parameter must be str
You should control the text of the query. The where clause shall allways be in the form WHERE colname=value [AND colname2=...] or (better) WHERE colname=? [AND ...] if you want to build a parameterized query.
So you want:
query = 'select * from StudentDB Where ' + ' AND '.join('"{}"=?'.format(col)
for col in sel.keys())
...
cur.execute(query, tuple(sel.values()))
In your code, the query is now a tuple instead of str and that is why the error.
I assume you want to execute a query like below -
select * from StudentDB Where "Roll number"=?
Then you can change the sql query like this (assuming you want and and not or) -
query = "select * from StudentDB Where {seq}".format(seq=" and ".join('"{}"=?'.format(k) for k in sel.keys()))
and execute the query like -
cur.execute(query, tuple(sel.values()))
Please make sure in your code the provided database is defined and contains the database name and studentDB is indeed the table name and not database name.

Pass Column Names into SQL statement in dynamic way - Python- SQL Server

query = ('SELECT ? from table', fields)
Example of 'fields' value = name, surname, date
I can put 'fields' in a list but I do not know how many (?) to put inside the query. Because, fields variable will include sometimes 5, sometimes 10 column names. I am trying to pass column names dynamically to the query.
How can I solve this problem?
A statement could be formed like so. Values will be like "(?, ?, ?, ?)" depending on the length of fields.
# create a comma separated list of question marks
# then surround with parenthesis
values = '('+', '.join(['?']*len(fields))+')'
query=('SELECT '+values+' from table',fields)
Not saying that this will work since you didn't share specifics of how you are connecting to or querying SQL Server.
Instead you could use the join str method:
table_name = 'MyTable'
fields = ['col1','col2','col3']
values = ', '.join(fields)
statement = 'SELECT '+values+' from '+table_name
query
'SELECT col1, col2, col3 from MyTable'
query=(statement)
Concatenate the query string
str1 = "SELECT "
for fieldname in fields:
str1 = str1 + fieldname + ", "
select_query_string = str1[0:-2] + " from " +table
and then use that in query
query=(select_query_string)

Why is SQL Inserting the Incorrect Value?

I'm writing a SQL query in Python that inserts new values to the end of a SQL table.
month = str(pd.to_datetime(datetime.datetime.strptime(current_month, "%B").replace(year = current_year)))[:7]
more_orders = int(total.iloc[-1][0] - total.iloc[-1][4] * total.iloc[-1][0])
more_sales = total.iloc[-1][1] - total.iloc[-1][5] * total.iloc[-1][1]
st.write(more_sales)
st.write(more_orders)
insertQuery = "insert into TABLE values ({}, 'First-time', {}, {}, 0.0)".format(month, more_orders, more_sales)
insertStmt = ibm_db.exec_immediate(connection, insertQuery)
customer_type = 'Returning'
more_orders = int(total.iloc[-1][0])
more_sales = total.iloc[-1][1]
insertQuery2 = "INSERT INTO TABLE VALUES ({}, 'Returning', {}, {}, 0.0)".format(month, more_orders, more_sales)
insertStmt2 = ibm_db.exec_immediate(connection, insertQuery2)
current_month and current_year are user-defined values.
There are two problems with the code that I don't understand.
When month = '2020-08', SQL records it as just '2012'.
Why does this happen? I even printed the value in the variable to make sure that it has '2020'-08'. It does.
Also, SQL inserts these values to the head of the table. I want to insert the values to the end of the table.
I'm using the IBM DB2 database.
2020-08 isn't a string, it's an arithmetic expression - "two thousand and twenty minus eight", which is 2012.
You could surround this expression with quotes so it's treated as a string, but the proper solution would probably be to use bind variables.

Return all values when a condition value is NULL

Suppose I have the following very simple query:
query = 'SELECT * FROM table1 WHERE id = %s'
And I'm calling it from a python sql wrapper, in this case psycopg:
cur.execute(query, (row_id))
The thing is that if row_id is None, I would like to get all the rows, but that query would return an empty table instead.
The easy way to approach this would be:
if row_id:
cur.execute(query, (row_id))
else:
cur.execute("SELECT * FROM table1")
Of course this is non idiomatic and gets unnecessarily complex with non-trivial queries. I guess there is a way to handle this in the SQL itself but couldn't find anything. What is the right way?
Try to use COALESCE function as below
query = 'SELECT * FROM table1 WHERE id = COALESCE(%s,id)'
SELECT * FROM table1 WHERE id = %s OR %s IS NULL
But depending how the variable is forwarded to the query it might be better to make it 0 if it is None
SELECT * FROM table1 WHERE id = %s OR %s = 0

Categories

Resources