Python MySQL connector SELECT statement issue - python

When I'm trying to format an SQL statement this way:
cursor.execute('SELECT (%s) FROM table WHERE id = 12345', (column,))
it doesn't work properly. Instead of returning values from the specified column, it just returns the name of the column. Any way to fix that?
It only works with formatted string, but according to reviews it is not the safest approach

You can't bind column names like that -you're binding a string literal with that name.
If you want to dynamically set the column names, you'll have to resort to string manipulation of some sort, e.g.:
cursor.execute(f'SELECT {column} FROM table WHERE id = 12345')
Of course if column is created by user-input, you'll have to sanitize it somehow.

Related

Replace column names with placeholder in sqlite

Can I replace a column name with a placeholder in while querying data from a table in sqlite?
Example:
db.execute("SELECT ? FROM currency WHERE user_id = ?", ( "usd", 1).fetchall()
It returns the placeholder which is 'usd" or any string I replaced it with.
Can I replace a column name with a placeholder in while querying data from a table in sqlite
No.
Placeholders exist to separate data (i.e. values) from code (i.e. the structure and meaning of the SQL statement). This way placeholders prevent SQL injection vulnerabilities.
Column names are code in SQL. If it was possible to parameterize them, the data/code separation would break, making your SQL vulnerable to injection attacks again, defeating the whole point of placeholders.
Also, you should not want to. It indicates a design flaw in your database if that appears as something you need. If your column name is variable, it should probably be a column itself.
So this
SELECT ? FROM currency WHERE user_id = ?
should probably be
SELECT data FROM currency WHERE user_id = ? AND currency_symbol = ?

SQLite nested query

I have been searching for quite some time but did not succeed to figure out how to select the id column from a table where either of the given other columns is not null.
I tried tied a nested query like:
SELECT id, name FROM spam_table WHERE (SELECT c.name FROM pragma_table_info('spam_table') c WHERE c.name LIKE '%ham%' OR c.name LIKE '%eggs%') IS NOT NULL
Is there any way that the inner PRAGMA returns the corresponding column names to be used for the outer query. And how assure the outer query is been put together using OR
Cheers.
Is there any way that the inner PRAGMA returns the corresponding
column names to be used for the outer query.
No. There is no "dynamic" column names (or table names) in sqlite.
One way to do it in python:
execute the pragma_table_info select
fetch the results
iterate the results and create the desired sql string
execute the created sql string
Thanks #DinoCoderSaurus for pointing out that there is no dynamic column names
The code I am using need some more pythonic style but in fact it I am running
for a in spam_table[0]: # Tables Header from the pragma_table_info(spam_table)
for i in eggs: # Search terms given by the UI
if i in a:
spam_eggs.append(self.spam_table[0].index(a))
Now I know which columns to check to extract the id

Syntax error when giving column name with parameter substitution

I am trying to create an SQL statement in Python that adds a column with a specific name to a table, but I am getting the error you see in the tittle.
I'm currently using this code.
columnname = 'note'
cur.execute("ALTER TABLE my_table_name ADD COLUMN %s MEDIUMTEXT", (columnname,))
That should create a column in my_table_name named note but it gives me this error:
MySQLdb._exceptions.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''note' MEDIUMTEXT' at line 1")
I know I should use normal string interpolation. But I want to keep adding columns like, column1 then column2 then column3 if the other ones are already storing data.
You are trying to use SQL "bind variables", also known as parameter substitution, for a column name. You Can't Do Thatâ„¢, You must specify column names (and table names) directly in your SQL statement.
Use normal string interpolation to construct your statements. Try something like this:
columnname = 'note'
cur.execute(f"ALTER TABLE my_table_name ADD COLUMN {columname} MEDIUMTEXT")
Or if you're using old-timey Python 2, use this:
columnname = 'note'
cur.execute("ALTER TABLE my_table_name ADD COLUMN " + columname + " MEDIUMTEXT")
You can, obviously, do this in a loop of some kind.
(Careful: adding columns to tables with many rows can be time consuming. And, adding columns to get around a UNIQUE index restriction is a very strange way to design a table. Instead, maybe, use a column without a UNIQUE index.)
If your columname values come from an end user, you must validate them before you use them. Otherwise, cybercreeps.

python sqlite named parameter containing dash

I'm trying to insert a record into an sqlite database using named parameters in python (with the sqlite3 module).
The values I want to insert are in a dictionary, but the dictionary keys might contain dashes, for example {'request-id': 100, 'year': '2015'}.
I'm trying to execute the following:
import sqlite3
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
cursor.execute('''CREATE TABLE IF NOT EXISTS requests (request_id text, year text)''')
query = '''INSERT INTO requests (request_id, year) VALUES (:request-id, :year)'''
cursor.execute(query, {'request-id': 100, 'year': '2015'})
conn.commit()
conn.close()
I get this error during the insert statement:
sqlite3.OperationalError: no such column: id
It seems like dashes are not well accepted as named parameters.
There are many workarounds for this, like creating a new dictionary where dashes in the keys are replaced by underscores, but I'd like to know if I could use some escaping technique or something else to avoid that.
Thanks for your help
The documentation for sqlite3_bind_* states that parameter names must be composed of alphanumeric characters, and doesn't mention a way of escaping them.
Your query is probably being parsed as :request - id, i.e. :request minus id, and since there's no such column id, SQLite throws an error.
(Also, as Prerak Sola points out, you create the table with a date column but try to insert to a year column which doesn't exist.)
SQL parameter names have no quoting or escaping mechanism; you have to use the same rules as for an unquoted identifier.

Wildcards in column name for MySQL

I am trying to select multiple columns, but not all of the columns, from the database. All of the columns I want to select are going to start with "word".
So in pseudocode I'd like to do this:
SELECT "word%" from searchterms where onstate = 1;
More or less. I am not finding any documentation on how to do this - is it possible in MySQL? Basically, I am trying to store a list of words in a single row, with an identifier, and I want to associate all of the words with that identifier when I pull the records. All of the words are going to be joined as a string and passed to another function in an array/dictionary with their identifier.
I am trying to make as FEW database calls as possible to keep speedy code.
Ok, here's another question for you guys:
There are going to be a variable number of columns with the name "word" in them. Would it be faster to do a separate database call for each row, with a generated Python query per row, or would it be faster to simply SELECT *, and only use the columns I needed? Is it possible to say SELECT * NOT XYZ?
No, SQL doesn't provide you with any syntax to do such a select.
What you can do is ask MySQL for a list of column names first, then generate the SQL query from that information.
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'your_table'
AND column_name LIKE 'word%'
let's you select the column names. Then you can do, in Python:
"SELECT * FROM your_table WHERE " + ' '.join(['%s = 1' % name for name in columns])
Instead of using string concatenation, I would recommend using SQLAlchemy instead to do the SQL generating for you.
However, if all you are doing is limit the number of columns there is no need to do a dynamic query like this at all. The hard work for the database is selecting the rows; it makes little difference to send you 5 columns out of 10, or all 10.
In that case just use a "SELECT * FROM ..." and use Python to pick out the columns from the result set.
No, you cannot dynamically produce the list of columns to be selected. It will have to be hardcoded in your final query.
Your current query would produce a result set with one column and the value of that column would be the string "word%" in all rows that satisfy the condition.
You can generate the list of column names first by using
SHOW COLUMNS IN tblname LIKE "word%"
Then loop through the cursor and generate SQL statement uses all the columns from the query above.
"SELECT {0} FROM searchterms WHERE onstate = 1".format(', '.join(columns))
This could be helpful: MySQL wildcard in select
In conclusion it is not possible in MySQL directly.
What you could do as a dirty workaround is get all the column names from the table with an initial query (http://dev.mysql.com/doc/refman/5.0/en/show-columns.html) and then compare in python if the name matches your pattern. Afterwards you could do the MySQL select statement with the found column names like this:
SELECT word1, word2, word3 from searchterms where onstate = 1;

Categories

Resources