Update MySQL field's row - python

I am using Python 2.7 and MySQLdb. I have made a database which has a table called test and in it two fields (id, firstname). The whole script is about counting and showing how many same firstnames do we have. The part of the script is like this right now but of course it doesn't work due to the 2nd line:
Value = int(input("Type your first name: "))
x.execute("UPDATE test SET id=(last id)+1 WHERE firstname=%s", (Value,))
What I am trying to do is type a Firstname from my keyboard and upload that to the database. If there is already that firstname in the table change his id which is a VARCHAR and make the new id = Last id + 1. For example if I type Doe and there is also Doe as a firstname in the database change Doe's row id number which is 1 by adding 1 and making it 2.

Sorry for the late answer.
I highly suggest to make the ID an INT with AUTO INCREMENT and PRIMARY KEY in order to prevent duplicates, but this would not allow you to change it freely as you want.
You need to check if there is a duplicate of the name you wrote inside the database, am i right?
If there is not, add a new row.
If there is, increment that name's id by one.
In order to check if that name is already in the database, you will need to do a SQL query, then check the results and compare the names you found with the one you wrote.
First, the query to get the names already in the database.
Then, check if the name already exists.
Then again, update or insert a new line into the database.
x.execute("""SELECT firstname FROM test""")
for row in x:
result = row[0]
if result == name:
nameExists = True
else:
nameExists = False
if !nameExists:
x.execute("""INSERT INTO test(firstname, id) VALUES (%s), (%s)""", name, id)
else:
x.execute("""SELECT id FROM test WHERE firstname = %s""", name)
for row in x:
actualId = row[0]
actualId = actualId + 1;
x.execute("""UPDATE test SET id = %s WHERE firstname = %s""", actualId, name)
The code above may change based on your variable names or preferences.
Do not take it as working, and copy-paste it directly into your code.
I hope the answer will be satysfing and complete. If not, let me know. It's the first time i answer to a question, and i may have not done it properly.
Thank you for your understanding.

Related

Expected expression Pylance error in If Condition

I am trying to insert the API query response in to the SQL server database. On a particular field I need to check if the value of the field on the Query response is true or false , if it is false I need to insert 'F' if its true I need to insert 'T' a field in DB
cursor = sqlconn.cursor()
for index,row in roomsDF.iterrows():
cursor.execute("INSERT INTO SurplusMouse.RM_Room(ROOMID, NAME, DESCRIPTION, SHIPPING_FREEZE, UPDATEDNAME)\
values(?,?,?,?,?)"
,row['id']
,row['name']
,row['description']
, if row['shippingFreeze'] == false:
'F'
else:
'T'
,row['shippingFreeze'].split(' ', 1)
)
I see two errors here one on the cursor.execute(" as "(" was not closed and another issue is Expected expression Pylance erroron the if . This is my first Python script and not sure if I am missing something any help is greatly appreciated
It seems to me you are mixing two different concepts. You need to divide and conquer.
Retrieve the data, and create a variable for each value.
id = row['id']
name = row['name']
shippingFreeze = 'T' if row['shippingFreeze'] else 'F'
Then, create the execute command. Make sure that the shippingFreeze attribute comes correctly formatted as boolean.
Regards
L.

how can i pass both int and string values to an execute UPDATE of a table

I want to pass a string value and an integer value to a sqlite3 execute UPDATE command
the num var needs to be an Int type, and the ans var needs to be String type so I could change the table's contents properly.
the table:
q_conn = sqlite3.connect('questions_stack.db')
q_c = q_conn.cursor()
q_c.execute("""CREATE TABLE IF NOT EXISTS questions (
id INTEGER PRIMARY KEY,
topic TEXT,
username TEXT,
subject TEXT,
body TEXT,
likes INTEGER,
comments TEXT)
""")
here I'm trying to UPDATE a certain column of a certain row:
def update_comments():
q_c.execute("""SELECT comments FROM questions WHERE id = ?""", (int(num),))
previous_comments = q_c.fetchone()
q_c.execute("""UPDATE questions SET comments = ? WHERE id = ?""",
(str(previous_comments) + "\n" + str(ans), int(num)))
q_conn.commit()
however, in my questions sqlite3 database table the comments column update I made appears as:
(u'',)
comment1
and when the update_comments() function is called again the comments column contains:
(u"(u'',)\ncomment1",)
comment2
what is the problem? and how can I fix it? does it have anything to do with the fact i passed both INT and STRING values to the command?
The problem is that this statement:
previous_comments = q_c.fetchone()
assigns a tuple, not a string. This tuple consists of one item - initially an empty string, because that's how you initialize your database - but still it is a tuple and when you call str() on it, you get the string representing a tuple, ie. (u'',).
A proper way of doing it is either:
(previous_comments,) = q_c.fetchone()
or
previous_comments = q_c.fetchone()[0]
so that previous_comments is assigned a string value. Oh, and calling str() on a string is redundant, so you can simplify this:
q_c.execute("""UPDATE questions SET comments = ? WHERE id = ?""",
(str(previous_comments) + "\n" + str(ans), int(num)))
to:
q_c.execute("""UPDATE questions SET comments = ? WHERE id = ?""",
(previous_comments + "\n" + ans, int(num)))

How to write one function to delete from multiple sql tables using python

I am implementing a student database project which has multiple tables such as student,class,section etc
I wrote a delete_table function which takes parameters table name and value to delete a row from a specific table but there seems to be some sort of syntax error in my code :
def delete_tables(tab_name,attr,value):
c.execute("delete from table=:tab_name where attribute=:attr is value=:value ",{'tab_name':tab_name, 'attr': attr, 'value': value})
input :
delete_tables('section','sec_name','S1')
error text :
c.execute("delete from table=:tab_name where attribute=:attr is value=:value ",{'tab_name':tab_name, 'attr': attr, 'value': value})
sqlite3.OperationalError: near "table": syntax error
I've tried all mentioned answers and what y'all are suggesting is that it'll also be insecure even if it works out. So Do i Have to write functions to delete every table individually instead of going for one single function, and is there any other alternative to this problem where I need not keep on writing n functions for n number of tables?????
Thanks in Advance :))
The problem is that you can't use parametrized queries (that :tab_name) on things others than values (? not sure I am using the right term): table names, column names and SQL keywords are forbidden.
where age > :max_age is OK.
where :some_col > :max_age is not.
where age :comparison_operator :max_age is not OK.
Now, you can build your own query using string concatenation or f strings, but... 🧨 this is a massive, massive SQL injection risk. See Bobby Tables Not to mention that concatenating values into SQL query strings quickly runs into issues when you have to deal with characters, numbers or None. (None => NULL, characters need quotes, numbers dont).
You could possibly build a query using string substitutions that accept only known values for the table and column names and then drives the delete criteria value using a parametrized query on :value.
(While this seems restrictive, letting a random caller determine which tables to delete is just not safe in the least).
Something like:
delete_tables(tab_name,attr,value):
safe_tab_name = my_dict_of_known_table_names[tab_name]
safe_attr = my_dict_of_known_column_names[attr]
# you have to `=`, not `is` here👇
qry = f"delete from {safe_tab_name} where {safe_attr} = :value "
# not entirely sure about SQLite's bind/parametrized syntax.
# look it up if needed.
c.execute(qry, dict(value = value))
Assuming a user only enters value directly, that at least is protected from SQL injection.
You need to have a look at what will be the exact SQL command that will be executed in the python method.
For the method call delete_tables('section', 'sec_name', 'S1') the SQL command that will be generated will be
delete from table=section where attribute=sec_name is value=S1
This will be an invalid command in SQL. The correct command should be
delete from section where sec_name='S1'
So you need to change your python function accordingly. The changes that need to be done should be as follows:
def delete_tables(tab_name, attr, value):
c.execute("delete from :tab_name where :attr = ':value'",
{'tab_name': tab_name, 'attr': attr, 'value':value})
def delete_tables(tab_name, attr, value):
c.execute("delete from " + tab_name + "where " + attr + " = " + value)
I think something like that will work, the issue is that you are trying to modify an attribute but its name is always attribute, for that you would like to make it a parameter in order to properly handle it.
Hope it helped.
Edit:
Check this SQLite python
What the c.execute does is to 'execute' a SQL query, so, you can make something like c.execute("select * from clients") if you have a clients table.
execute makes a query and brings you the result set (if it is the case), so if you want to delete from your table using a normal SQL query you would type in the console delete from clients where client_id = 12 and that statement will delete the client with id equal to 12.
Now, if you are using SQLite in python, you will do
c.execute("delete from clients where client_id = 12")
but as you wish it to be for any table and any field (attribute) it turns in the table name, the field name and the value of that field being variables.
tableName = "clients"
field = "client_id"
value = "12" #must be string because you would have to cast it from int in the execute
"""
if value is a varchar you must write
value = "'12'" because the '' are needed.
"""
c.execute("delete from " + tableName + " where " + field + " = " + value)
and in the top of that, as you want it to be a function
def delete_tables(tableName, field, value):
c.execute("delete from " + tableName+ "where " + field + " = " + value)
Edit 2:
aaron's comment is true, it is not secure, the next step you would do is
def delete_tables(tab_name, attr, value):
#no ':value' (it limits the value to characters)
c.execute("delete from :tab_name where :attr = :value",
{'tab_name': tab_name, 'attr': attr, 'value':value})
It is from Vatsal's answer

Python updating DB column issue with overwrite?

I have a simple function which should update a certain column for certain users:
for key, group in groupby(list_i):
print key, type(key), len(list(group)), type(len(list(group)))
setattr(User.query.filter_by(id=key).first(), "number_of_rooms", len(list(group)))
db_session.commit()
I have a list (list_i) which has the data, simply look at the print:
The data is correct, the first number is the id of the user and the second is the value which should be assign to column number_of_rooms
The problem is it sets all values of the users to 0. I assume it is somehow an override issue of the last user, I dont know. The thing is if I change it to:
setattr(User.query.filter_by(id=key).first(), "number_of_rooms", 2)
It will change the value to 2 for all users with id=key so the function works. I am here very confused, because len(list(group)) is a simple integer and it should work.
EDIT:
I double checked everything, I also made an other test with a variable (t) which increments by 1 and added an onther print to check everything, with the variable it also works, how is that possible?
t = 0
for key, group in groupby(list_i):
print key, type(key), len(list(group)), type(len(list(group)))
my_user = User.query.filter_by(id=key).first()
setattr(my_user, "number_of_rooms", t)
print my_user.number_of_rooms
t+=1
db_session.commit()
The value of number_of_rooms changes:
As Roman Mindlin and glibdud have specified, list(group) can only be used once. Since group is of type <type 'itertools._grouper'>, after you iterate over group once (e.g. by calling list() on it), it's exhausted. The key is to save the list(group) inside a variable.
Here is the code that fixes the issue:
for key, group in groupby(list_i):
l_group = list(group)
print(l_group)
my_user = User.query.filter_by(id=key).first()
setattr(my_user, "number_of_rooms", len(l_group))
db_session.commit()

Querying Sqlite db with variable

Trying to learn Sqlite and I'm not sure I understand why I can't get this code to work:
def get_bday(self):
name = self.input_name()
self.c.execute('SELECT * FROM birthdays WHERE name =?', name)
for row in self.c.fetchall():
print(row)
The name variable is being returned from another method. For this example, I am using "joe smoe" without the quotes as the name variable to perform the query with. When I run the above code I get:
self.c.execute('SELECT * FROM birthdays WHERE name =?', name)
sqlite3.ProgrammingError: Incorrect number of bindings supplied. The current statement uses 1, and there are 8 supplied.
The word "joe smoe" is 8 bindings long if you count the space. But I have no idea what that means. I assumed I could simply pass a variable right to Sqlite just as easily as I pass variables around in Python but that doesn't appear to be the case. I think it has something to do with my very poor understanding of tuples.
SQLite is currently thinking you want to query each individual letter of 'joe smoe'.
All you have to do to avoid this is put name in a container of some kind: a tuple or a list for example:
def get_bday(self):
name = self.input_name()
self.c.execute('SELECT * FROM birthdays WHERE name =?', (name,))
# ^ ^^
for row in self.c.fetchall():
print(row)

Categories