I'd like to grab a specific value from a row based on a random variable. Here's an example table the PID column is an "auto-increment primary key integer" and the other 2 columns are TEXT
example-table
PID NAME PHONE
--- ---- -----
1 bill 999-9999
2 joe 888-8888
I'd like to throw a random variable at the table
randomVariable = raw_input('Enter something: ')
> 1
and have the code return the name
> bill
I know I can use something like...
randomVariable = raw_input('Enter something: ')
sql = ("SELECT name FROM example_table WHERE pid='%s'" % randomVariable)
result = cursor.execute(sql)
print result
> bill
Apparently using '%s' isn't secure and it is suggested to use '?' in it's place.
randomVariable = raw_input('Enter something: ')
sql = ("SELECT name FROM example_table WHERE pid=?", randomVariable)
result = cursor.execute(sql)
print result
But this doesn't seem to work for me. I end up with...
"ValueError: operation parameter must be str or unicode"
I realize I could just grab all the rows and put them into a variable which I could then iterate over till I find what I'm looking for but I'm thinking that wouldn't be very efficient with a large database. can anyone help point me in the right direction with this?
I believe you're meant to use it like this
randomVariable = raw_input('Enter something: ')
sql = "SELECT name FROM example_table WHERE pid=?"
result = cursor.execute(sql, randomVariable)
print result
Validate the user input, and %s is fine. Storing your rows and putting them into a list is not a good idea at all, since the amount of rows will grow over time, taking up a huge amount of memory when not even in use. To guard against SQL injection, you could validate input using something like a typecast to an int, put that in a try/except block, and this would stop all malicious input such as ' OR 1=1--
Related
This is the code :
import mysql.connector as mariadb
import time
import random
mariadb_connection = mariadb.connect(user='root', password='xxx', database='UniqueCode',
port='3306', host='192.168.xx.xx')
cursor = mariadb_connection.cursor()
FullChar = 'CFLMNPRTVWXYK123456789' # i just need that char
total = 5000
count = 10
limmit = 0
count = int(count)
entries = []
uq_id = 0
total_all = 0
def inputDatabase(data):
try:
maria_insert_query = "INSERT INTO SN_UNIQUE_CODE(unique_code) VALUES (%s)"
cursor.executemany(maria_insert_query, data)
mariadb_connection.commit()
print("Commiting " + str(total) + " entries..")
except Exception:
maria_alter_query = "ALTER TABLE UniqueCode.SN_UNIQUE_CODE AUTO_INCREMENT=0"
cursor.execute(maria_alter_query)
print("UniqueCode Increment Altered")
while (0 < 1) :
for i in range(total):
unique_code = ''.join(random.sample(FullChar, count))
entry = (unique_code)
entries.append(entry)
inputDatabase(entries)
#print(entries)
entries.clear()
time.sleep(0.1)
Output:
Id unique_code
1 N5LXK2V7CT
2 7C4W3Y8219
3 XR9M6V31K7
The code above runs well, the time it takes to generate it is also fast, the problem I faced was when the unique_code stored in the tuple was to be entered into mariadb, to avoid data redundancy, i added a unique index in the unique_code column.
The more data that is entered, the more checking of the unique code that will be entered, which makes the process of entering data into the database longer.
From that problem, how can I generate 1 billion data to the database in a short time?
note: the process will slow down when the unique_code that enters the database is > 150 million unique_codes
Thank's a lot
The quick way
If you want to insert many records into the database, you can bulk-insert them as you do now.
I would recommend you disable the keys on the table before inserting and skip the check for unique. Else you will have a bad time like #CryptoFool mentioned.
ALTER TABLE SN_UNIQUE_CODE DISABLE KEYS;
<run code>
ALTER TABLE SN_UNIQUE_CODE ENABLE KEYS;
If I were you, then I would try to play around with the maximum you can insert at once. Try changing max_allowed_packet variable in MariaDB if necessary.
The table
It seems like your unique_code could be a natural key. Therefore you could remove the auto_incremented variable, it won't bring much performance but it is a start.
I am trying to make a mock database to store film timings and allow the user to make bookings from the list. I have run into a problem where I am trying to take the ticket price from a table and multiply it by the number of tickets to get a final price. When I try to run the code it says that you cannot multiply a list by and int. Has anyone an idea on how to cast the value in a table in SQL into an int? Here is the relevant code:
showTime = input("Enter showtime: ")
filmRequest = input("Enter the film you want to watch: ").title()
priceSelection_ = "SELECT price FROM films WHERE film = ? AND timings = ?"
parSel_ = (filmRequest, showTime)
cursor.execute(priceSelection_, parSel_)
x = cursor.fetchall()
priceCalc_ = numTick_ * x
print(priceCalc_)
You do not cast it. You must select the appropriate value from the result set. In your case, it should be
x = cursor.fetchall()[0][0]
But you may need to further cast/process the value depending on how it is stored.
The following code works with insert query, but not with update and delete.
prono=int(input("Enter the poduct no :"))
sql_1="select * from product where prno=%s"
mycursor.execute(sql_1,prono)
myresult=mycursor.fetchall()
mydb.commit()
for x in myresult:
print(x)
#details printed
#req. details for updation
print("Please enter the new details of the product")
a=str(input("Enter the new name : "))
b=int(input("Enter the new price : "))
sql_2="update product set name=%s ,price=%s where prno=%s"
set1=(a,b,prono)
mycursor.execute(sql_2,set1)
mydb.commit
print("Product modified")
The error I'm getting is 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 '%s'
You seem to be trying to convert a string to an int:
a=int(input("Enter the new name : "))
This probably is not working with your table layout.
Try:
a=input("Enter the new name : ")
Also you are using "No" and "NO" in your queries.
It's not the spelling of no, it's a reserved word. This seems to be valid:
UPDATE
product
SET
myname = 'string',
myprice = 123
WHERE
myno = 1;
(of course you need to change your column names in the database table for this to work)
You are using NO as column name, but is a MySql reserved word, you should use backticks for it like this for sql_1 & sql_2:
sql_1="select * from product where `No`=%s"
sql_2="update product set name=%s ,price=%s where `NO`=%s"
But the better solution it is not using reserved words as column names.
EDIT
Also, your sql_1 query is wrong, you donĀ“t need to use (). If you do it, you get a touple with a string, not a string
I am trying to get a value from an SQLite3 database and put that into a variable called FilmLikes, I then want to add one to it and I store that in the variable NewFilmLikes. I then try to change the value of this box in my database to the 'NewFilmLikes', however I always get this problem:
ValueError: invalid literal for int() with base 10: 'NewFilmLikes'
Here is the code showing that:
FilmLikes=i[2]
NewFilmLikes=(int(FilmLikes))+1
filmUpdate=("UPDATE HORRORALL SET likes = ? WHERE number = 1"(NewFilmLikes))
c.execute(filmUpdate)
conn.commit()
Here is the code for i:
for i in find_film:
print('')
print('Number',(i[0]))
print(i[1])
filmChoice=int(input('Please choose which number you would like to like: '))
if filmChoice==1:
find_film=c.execute("SELECT * FROM HORRORALL")
for i in find_film:
if i[0]==filmChoice:
## FilmLikes=i[2]
try:
x=(int(i[2]))+1
except:
pass
## FilmLikes=i[2]
## NewFilmLikes=(int(str(FilmLikes)))+1
filmUpdate=("UPDATE HORRORALL SET likes = ? WHERE number = 1"(x))
c.execute(filmUpdate)
conn.commit()
Without knowing much more about your setup, it's hard to answer this properly.
Mind you, the specific error you refer to (ValueError: invalid literal for int() with base 10: 'NewFilmLikes') often occurs when you get a decimal rather than an integer.
Here's a sort of general answer.
It's good practice not to use SELECT * because it hides what you are trying to retrieve. Specify, e.g SELECT film_id, file_name, no_of_likes FROM horrorall as this way you can see what you are retrieving and the positions.
You're retrieving the entire list of films with find_film and then looping through to find which one. SQL has a find function, it's called WHERE and you are using it in the film_update section. If you have the ID or Name inputted by the user, you can then call only the record you need. E.g. "SELECT film_id, file_name, no_of_likes FROM horrorall WHERE film_id = ?" (filmChoice,)
Note that parameterised queries use a tuple, even if there is only one parameter - hence it is (filmChoice,) with a comma (and for filmUpdate you would need (x,))
filmUpdate will only ever update the first film. I assume that because your if ... loop continues through all the possible options? You can shortly this by putting another ? in there for your WHERE e.g. filmUpdate=("UPDATE HORRORALL SET likes = ? WHERE number = ?"(x,i[0]))
How does the user know what film to select? You aren't retrieving the list until they give you a number!
Putting all of this together, here is an example. Note this is far from the ideal way of doing it, I don't want to throw too many ideas at you in one go!
# Get the whole list of films to show to the user
find_film = c.execute("SELECT film_id, film_name FROM HORRORALL")
# Present the list for selection
for films in find_film:
print(str(films[0]) + '. ' + films[1])
# Get the users input as an integer
filmChoice = int(input('Please choose which number you would like to like: '))
# Fetch the number of likes of the selected film
film_likes = c.execute('SELECT likes FROM HORRORALL WHERE film_id = ?' (filmChoice,))
# Send the update back to the database
c.execute("UPDATE HORRORALL SET likes = ? WHERE film_id = ?"(int(film_likes[0]) + 1, filmChoice)
conn.commit()
query = "SELECT serialno from registeredpcs where ipaddress = "
usercheck = query + "'%s'" %fromIP
#print("query"+"-"+usercheck)
print(usercheck)
rs = cursor.execute(usercheck)
print(rs)
row = rs
#print(row)
#rs = cursor.rowcount()
if int(row) == 1:
query = "SELECT report1 from registeredpcs where serialno = "
firstreport = query + "'%s'" %rs
result = cursor.execute(firstreport)
print(result)
elif int(row) == 0:
query_new = "SELECT * from registeredpcs"
cursor.execute(query_new)
newrow = cursor.rowcount()+1
print(new row)
What I am trying to do here is fetch the serialno values from the db when it matches a certain ipaddress. This query if working fine. As it should the query result set rs is 0. Now I am trying to use that value and do something else in the if else construct. Basically I am trying to check for unique values in the db based on the ipaddress value. But I am getting this error
error: uncaptured python exception, closing channel smtpd.SMTPChannel connected
192.168.1.2:3630 at 0x2e47c10 (**class 'TypeError':'int' object is not
callable** [C:\Python34\lib\asyncore.py|read|83]
[C:\Python34\lib\asyncore.py|handle_read_event|442]
[C:\Python34\lib\asynchat.py|handle_read|171]
[C:\Python34\lib\smtpd.py|found_terminator|342] [C:/Users/Dev-
P/PycharmProjects/CR Server Local/LRS|process_message|43])
I know I am making some very basic mistake. I think it's the part in bold thats causing the error. But just can't put my finger on to it. I tried using the rowcount() method didn't help.
rowcount is an attribute, not a method; you shouldn't call it.
"I know I am making some very basic mistake" : well, Daniel Roseman alreay adressed the cause of your main error, but there are a couple other mistakes in your code:
query = "SELECT serialno from registeredpcs where ipaddress = "
usercheck = query + "'%s'" % fromIP
rs = cursor.execute(usercheck)
This part is hard to read (you're using both string concatenation and string formatting for no good reason), brittle (try this with `fromIP = "'foo'"), and very very unsafe. You want to use paramerized queries instead, ie:
# nb check your exact db-api module for the correct placeholder,
# MySQLdb uses '%s' but some other use '?' instead
query = "SELECT serialno from registeredpcs where ipaddress=%s"
params = [fromIP,]
rs = cursor.execute(query, params)
"As it should the query result set rs is 0"
This is actually plain wrong. cursor.execute() returns the number of rows affected (selected, created, updated, deleted) by the query. The "resultset" is really the cursor itself. You can fetch results using cursor.fetchone(), cursor.fetall(), or more simply (and more efficiently if you want to work on the whole resultset with constant memory use) by iterating over the cursor, ie:
for row in cursor:
print row
Let's continue with your code:
row = rs
if int(row) == 1:
# ...
elif int(row) == 0:
# ...
The first line is useless - it only makes row an alias of rs, and badly named - it's not a "row" (one line of results from your query), it's an int. Since it's already an int, converting it to int is also useless. And finally, unless 'ipadress' is a unique key in your table, your query might return more than one row.
If what you want is the effective value(s) for the serialno field for records matching fromIP, you have to fetch the row(s):
row = cursor.fetchone() # first row, as a tuple
then get the value, which in this case will be the first item in row:
serialno = row[0]