In my Python code when I ask the user to input a string to SELECT, it works but when I try the UPDATE using the same input doesn't allow me to execute
Here is my code after the connection has been successfully done
curs = connection.cursor()
str_input1 = str(input("Input : "))
str_input2 = str(input("Input : "))
statement = "UPDATE table SET variable1 = "+str_input1+" WHERE name = "+str_input2
curs.execute(statement)
connection.commit
In theory this following code should work and update the variable, but instead I get the error at line curs.execute(statement) saying
cx_Oracle.DatabaseError: ORA-00904: John: invalid identifier
John was the str_input2 for where clause
Maybe its the format that was giving me an error but I'm not too sure.
Can someone point out what was the problem with my code?
The error is because you're not quoting the values. You'd get the exact same error from a SELECT statement.
These statements search for rows where the name column matches the string John:
SELECT * FROM table WHERE name = "John"
UPDATE table SET variable1 = "Hi" WHERE name = "John"
These statements search for rows where the name columns matches the John column—and if there is no John column, that's an error:
SELECT * FROM table WHERE name = John
UPDATE table SET variable1 = "Hi" WHERE name = John
So, you could fix this by just putting quotes around the values.
But you really, really, really shouldn't. This opens you up to SQL injection attacks, and stupid bugs where you don't quote or escape special characters properly, and performance problems where the database engine can't tell that you're running the same query over and over, and so on.
What you want to do is to use SQL parameters, instead of trying to format the string. I don't remember which parameter style cx_Oracle uses, but you can just import cx_Oracle; print(cx_Oracle.paramstyle), and look it up in the table to find out. And then do something like:
statement = "UPDATE table SET variable1 = :v WHERE name = :n"
curs.execute(statement, {'v': str_input1, 'n': str_input2})
Also, a few side notes:
connection.commit doesn't do anything; you're just referencing the commit method, not calling it. You need parentheses: connection.commit()
str(input()) is pointless. The input function always returns a string, so there's no reason to call str on it. (Unless you're using Python 2.x, in which case you should be using raw_input(), which returns a string, instead of using input to eval the string—opening up the same kinds of security problems as the SQL injection attack above—only to convert it back to a string.)
Related
I am new to working on Python. I m not able to understand how can I send the correct input t0 the query.
list_of_names = []
for country in country_name_list.keys():
list_of_names.append(getValueMethod(country))
sql_query = f"""SELECT * FROM table1
where name in (%s);"""
db_results = engine.execute(sql_query, list_of_names).fetchone()
Give the error " not all arguments converted during string formatting"
As implied by John Gordon's comment, the number of placeholders in the SQL statement should match the number of elements in the list. However SQLAlchemy 2.0+ no longer accepts raw SQL statements. A future-proof version of the code would be:
import sqlalchemy as sa
...
# SQL statements should be wrapped with text(), and should used
# the "named" parameter style.
sql_query = sa.text("""SELECT * FROM table1 where name in :names)"""
# Values should be dictionaries of lists of dictionaries,
values = {'names': list_of_names}
# Execute statements using a context manager.
with engine.connect() as conn:
db_results = conn.execute(sql_query, values).fetchone()
If I know right, there are a simpler solution. If you write curly bracets {}, not bracets (), and you place inside the bracets a variable, which contains the %s value, should work. I don't know, how sql works, but you should use one " each side, not three.
Sorry, I'm not english. From this, maybe I wasn't help with the question, because I don't understand correctly.
I am wanting to run a Presto SQL query in a for loop so that the query will pull hourly data based on my date variables.
Example query is along the lines of:
x = datetime.strptime('12-10-22', '%d-%m-%y').date()
y = datetime.strptime('13-10-22', '%d-%m-%y').date()
for dt in rrule.rrule(rrule.HOURLY, dtstart=nextProcStart, until=nextProcEnd):
sql_query = "SELECT SUM(sales) FROM a WHERE date between x and y"
I will note I'm using the syntax of writing the SQL query as a variable so along the lines of:
sql_query = """ SELECT... FROM..."""
I have tried just adding the variables into the query but no luck. Unsure what steps will work.
I've also tried using .format(x,y) at the end of my SQL query but keep getting an error saying
KeyError: 'x'
Remember that your SQL statement is no more than a string, so you just need to know how to incorporate a variable into a string.
Try:
sql_query = "SELECT SUM(sales) FROM a WHERE date between {} and {}".format(x, y)
Read How do I put a variable’s value inside a string (interpolate it into the string)? for more info or alternative methods.
Hopefully this answers your immediate question above on how to incorporate variable into string and get your code, as is, to work. However, as #nbk, mentions in comment below, this method is NOT recommended as it is insecure.
Using concatenations in SQL statements like this does open the code up to injection attacks. Even if your database does not contain sensitive information, it is bad practice.
Prepared statements have many advantages, not least of all that they are more secure and more efficient. I would certainly invest some time in researching and understanding SQL prepared statements.
i have a table that records the attendance of students. The table have 4 columns , one for the student ID and the other are for week1 ,week2 and week3 (All the columns are integers). The attendance is recorded by entering only 1 for the certain week ( or zero if he was absent) . My problem is here , when i want to add the attendance i use the update statement as follow :
week_number=input('enter the week ( week1/week2/week3')
id=int(input('enter student ID'))
sat="UPDATE Attendance2 SET %s=1 WHERE ID=%s "
cur.execute(sat, (week_number,id,))
conn.commit()
As you can see ,I don't know what the column that the user will refer to ( it is a variable ) , so i have used %s behind the SET, but it is wrong.
Here is the error :
mysql.connector.errors.ProgrammingError: 1064 (42000): 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 ''week1'=1 WHERE ID=300' at line 1
Any help please ? How do i write a variable column name in a execute statement ?
Note that i am updating only the attended students , that's why there is 1 in the UPDATE statement
AFAICT, it's supposed to be ok to surround keys with quotes. But as you say that all datatypes are integers, your values have no issues.
And because it says this is a syntax error (and not column issue, what it would yell if it was not finding week1), it leads me to believe the issues actually are your quotes, which if not expected by mysql's SQL grammar, it would indeed yell about a syntax issue.
mysql […] near ''week1'=1 WHERE ID=300' at line 1
^
What makes a python string gets surrounded by single quotes? It's the repr() version of the string, the one you get when you type a string on the REPL:
>>> x = '42'
>>> x
'42'
>>> print(repr(x))
'42'
>>> print(x)
42
I'm not sure why this issue would happen to you. A good ideais to use the python form of formatting strings, and run:
sat="UPDATE Attendance2 SET {}=1 WHERE ID={}".format(week_number, id)
if it still happens, you can try to force typing of week_number into a str(), using str(week_number).
Talking about formatting strings, you might want to enforce the typing, so you avoid surprises:
sat="UPDATE Attendance2 SET {:s}=1 WHERE ID={:d}".format(str(week_number), int(id))
which will make sure week_number is a valid string and formatted as a string, and id is a valid integer and formatted as an integer.
Nota Bene: avoid using id in your code, which is a python reserved keyword, and instead use _id, ident or idx. It's always a good idea to avoid shadowing global python keywords.
HTH
try
sat="UPDATE Attendance2 SET " + week_number + "='1' WHERE ID='" + student_id + "'"
cur.execute(sat)
...
hope this helps ^^-d
PS: It is easier to test the code if you set the variables week_number and student_id "hardwired", e.g.:
week_number = "week1"
student_id = "1"
PPS: The way you design your table is a bit redundant which may lead to update errors in the future. It might e.g. be better to have a 2 column table with the student_id and attended_week(as 1,2,3).
I'm trying to insert some values in a table, and although the rows are being created, the values aren't being recorded. Here is my code:
for i in range(2,6):
for team in ul[i]:
name = team.string #string from html element
print(name) #this works just fine, and prints the desired name
cur.execute("INSERT INTO teams (Name) VALUES(name)")
conn.commit()
Now if I put VALUES("Test String") instead, it works, 30 rows are added (what I want), and all with the Name: "Test String".
Yet when I put in my name variable, the rows are added as well, but the column values are empty. The column I'm putting the strings in is VARCHAR. Is there something I don't know about how the SQL statement is interpreted in the case of Python string variables?
It appears that the SQL statement is a simple string and he name variable isn't being inserted into it.
Perhaps you could do something like this:
sql = """INSERT INTO teams (Name) VALUES({0})""".format(json.dumps(name))
cur.execute(sql)
I use json.dumps(myVar) to escape special characters, e.g. quotes, etc... that might break the SQL insert statement.
Sometimes it's helpful to print out the SQL statement and try to run it in a client (e.g. MySQL Workbench), in order to see what changes, if any, are necessary to generate syntactically correct statements.
I'm making a program that is a user interface for quizes set by teachers in a primary school. I am trying this query which is using data typed in by the user on the previous page. it is looking for people in the database who match the username and quiz number concerned. this is so the teacher can see how well pupils are doing on certain quizes.
Here is my code.
dbDatabase = sqlite3.connect('c:\\xampp\\cgi-bin\\MakingATable.db')
cuDatabase = dbDatabase.cursor()
Fieldstorage = cgi.FieldStorage() #what you typed in on the webpage
Quizno = Fieldstorage.getvalue("quizno")
UserID = Fieldstorage.getvalue("username")
#print (Quizno)
#print (UserID)
cuDatabase.execute ("""
SELECT Result
FROM resultstable
WHERE QuizID = '""" + str(Quizno) + """
AND UserID = '""" + UserID + "'")
for (row) in cuDatabase:
print (row)
dbDatabase.commit()
cuDatabase.close()
Here is the error message i am getting when i run my webpage:
40 FROM resultstable
41 WHERE QuizID = '""" + str(Quizno) + """
=> 42 AND UserID = '""" + UserID + "'")
43
44 for (row) in cuDatabase:
AND undefined, UserID = 'HuPa1'
OperationalError: near "HuPa1": syntax error
args = ('near "HuPa1": syntax error',)
with_traceback = <built-in method with_traceback of OperationalError object>
Also should I use an OR instead of AND so that if the user hasn't done that quiz it will display any quiz the user does. or so that if lots of people have done one Quiz then the teacher will see everyone who, for example, have done quiz 1?
You should use SQL parameters:
cuDatabase.execute ("""
SELECT Result
FROM resultstable
WHERE QuizID = ?
AND UserID = ?""", (Quizno, UserID))
The ? placeholders will be replaced by your values, automatically quoted to prevent SQL injection attacks (and operational errors).
Quoting from the sqlite3 module documentation:
Usually your SQL operations will need to use values from Python variables. You shouldn’t assemble your query using Python’s string operations because doing so is insecure; it makes your program vulnerable to an SQL injection attack (see http://xkcd.com/327/ for humorous example of what can go wrong).
Instead, use the DB-API’s parameter substitution. Put ? as a placeholder wherever you want to use a value, and then provide a tuple of values as the second argument to the cursor’s execute() method. (Other database modules may use a different placeholder, such as %s or :1.)
Use a separate query to ask the database for other quizzes if this query doesn't return a result; if you use OR instead of AND otherwise, you will get both quizz results that other users have done, and anything this user has completed.
The best solution is to use prepared statement:
cuDatabase.execute("SELECT Result FROM resultstable WHERE QuizID=? AND UserID=?", Quizno, UserID)
In prepared statement mode all variables are replaced by question marks in query text and are parameters to execute(). But not all databases or db drivers support it. Sometimes instead of question mark you will have to use %s (one of PostgreSQL drivers works this way).
Worse, but working solution is to use Python % operator, but with this solution you will have to use your own quote() function that escapes dangerous characters that may appear in data (prevents from SQL injection):
cuDatabase.execute("SELECT Result FROM resultstable WHERE QuizID='%s' AND UserID='%s'" % (quote(Quizno), quote(UserID)))