Quotations not working in PostgreSQL Queries - python

I have the following table
create table players (name varchar(30), playerid serial primary key);
And I am working with the script:
def registerPlayer(name):
"""Registers new player."""
db = psycopg2.connect("dbname=tournament")
c = db.cursor()
player = "insert into players values (%s);"
scores = "insert into scores (wins, matches) values (0, 0);"
c.execute(player, (name,))
c.execute(scores)
db.commit()
db.close()
But when I try and register a player with the argument in quotes as so:
registerPlayer("Any Name")
It doesn't work... Now, if I directly enter the query into psql, it works if I only use single quotes as so
INSERT INTO players VALUES ('Any Name');
But not if I use "Any Name". If I use the "", it tells me:
ERROR: column "Any Name" does not exist Now, this is a problem if I want to enter a name in such as Bob O'Neal, because it will close off that entry after the O.
The quotes were working fine the other day, and I went to format so that all the SQL queries were capitalized, and everything stopped working. I returned to the code that was working fine, and now nothing is working!

Double-quotes in SQL are not strings - they escape table, index, and other object names (ex. "John Smith" refers to a table named John Smith). Only single quoted strings are actually strings.
In any case, if you are using query parameters properly (which, in your example code, you seem to be), you should not have to worry about escaping your data. Simply pass the raw values to execute (ex. c.execute(player, ("Bob O'Niel",)))

Related

column "e" of relation "analysis_result" does not exist

connection to postgresql database has been connected successfully.but while executing below query i am getting some kind of error which looks like :
column "e" of relation "analysis_result" does not exist
LINE 1: INSERT INTO analysis_result(user_id,E,A,C,N,O,total) VALUES ...
cursor = connection.cursor()
print("inside execution ")
cursor.execute("INSERT INTO analysis_result(user_id,E,A,C,N,O,total) VALUES (%s,%s,%s,%s,%s,%s,%s)",Result_lst)
i understand what is the error .i have to put each of E A C N O in quotes but while quoting them my sql query becomes invalid .Please give me a solution i am scraching my head for quite sometime now.
and Result_lst=[1,20,14,14,38,8]. Result_lst will be dyanamic values in integer forms.
If the column name contains upper case characters, you must surround it with double quotes, otherwise PostgreSQL will fold it to lower case (note the error message).
But you cannot simply use double quotes because that's what you used for the Python string.
Either use single quotes with the Python string:
cursor.execute('INSERT INTO analysis_result(user_id,"E","A","C","N","O",total) ...', Result_lst)
or escape the double quotes:
cursor.execute("INSERT INTO analysis_result(user_id,\"E\",\"A\",\"C\",\"N\",\"O\",total) ...", Result_lst)

Too many server roundtrips w/ psycopg2

I am making a script, that should create a schema for each customer. I’m fetching all metadata from a database that defines how each customer’s schema should look like, and then create it. Everything is well defined, the types, names of tables, etc. A customer has many tables (fx, address, customers, contact, item, etc), and each table has the same metadata.
My procedure now:
get everything I need from the metadataDatabase.
In a for loop, create a table, and then Alter Table and add each metadata (This is done for each table).
Right now my script runs in about a minute for each customer, which I think is too slow. It has something to do with me having a loop, and in that loop, I’m altering each table.
I think that instead of me altering (which might be not so clever approach), I should do something like the following:
Note that this is just a stupid but valid example:
for table in tables:
con.execute("CREATE TABLE IF NOT EXISTS tester.%s (%s, %s);", (table, "last_seen date", "valid_from timestamp"))
But it gives me this error (it seems like it reads the table name as a string in a string..):
psycopg2.errors.SyntaxError: syntax error at or near "'billing'"
LINE 1: CREATE TABLE IF NOT EXISTS tester.'billing' ('last_seen da...
Consider creating tables with a serial type (i.e., autonumber) ID field and then use alter table for all other fields by using a combination of sql.Identifier for identifiers (schema names, table names, column names, function names, etc.) and regular format for data types which are not literals in SQL statement.
from psycopg2 import sql
# CREATE TABLE
query = """CREATE TABLE IF NOT EXISTS {shm}.{tbl} (ID serial)"""
cur.execute(sql.SQL(query).format(shm = sql.Identifier("tester"),
tbl = sql.Identifier("table")))
# ALTER TABLE
items = [("last_seen", "date"), ("valid_from", "timestamp")]
query = """ALTER TABLE {shm}.{tbl} ADD COLUMN {col} {typ}"""
for item in items:
# KEEP IDENTIFIER PLACEHOLDERS
final_query = query.format(shm="{shm}", tbl="{tbl}", col="{col}", typ=i[1])
cur.execute(sql.SQL(final_query).format(shm = sql.Identifier("tester"),
tbl = sql.Identifier("table"),
col = sql.Identifier(item[0]))
Alternatively, use str.join with list comprehension for one CREATE TABLE:
query = """CREATE TABLE IF NOT EXISTS {shm}.{tbl} (
"id" serial,
{vals}
)"""
items = [("last_seen", "date"), ("valid_from", "timestamp")]
val = ",\n ".join(["{{}} {typ}".format(typ=i[1]) for i in items])
# KEEP IDENTIFIER PLACEHOLDERS
pre_query = query.format(shm="{shm}", tbl="{tbl}", vals=val)
final_query = sql.SQL(pre_query).format(*[sql.Identifier(i[0]) for i in items],
shm = sql.Identifier("tester"),
tbl = sql.Identifier("table"))
cur.execute(final_query)
SQL (sent to database)
CREATE TABLE IF NOT EXISTS "tester"."table" (
"id" serial,
"last_seen" date,
"valid_from" timestamp
)
However, this becomes heavy as there are too many server roundtrips.
How many tables with how many columns are you creating that this is slow? Could you ssh to a machine closer to your server and run the python there?
I don't get that error. Rather, I get an SQL syntax error. A values list is for conveying data. But ALTER TABLE is not about data, it is about metadata. You can't use a values list there. You need the names of the columns and types in double quotes (or no quotes) rather than single quotes. And you can't have a comma between name and type. And you can't have parentheses around each pair. And each pair needs to be introduced with "ADD", you can't have it just once. You are using the wrong tool for the job. execute_batch is almost the right tool, except it will use single quotes rather than double quotes around the identifiers. Perhaps you could add a flag to it tell it to use quote_ident.
Not only is execute_values the wrong tool for the job, but I think python in general might be as well. Why not just load from a .sql file?

dynamic table mysqldb python string/int issue

I am receiving an error when trying to write data to a database table when using a variable for the table name that I do not get when using a static name. For some reason on the line where I insert, if I insert an integer as the column values the code runs and the table is filled, however, if I try to use a string I get a SQL syntax error
cursor = db.cursor()
cursor.execute('DROP TABLE IF EXISTS %s' %data[1])
sql ="""CREATE TABLE %s (IP TEXT, AVAILIBILITY INT)""" %data[1]
cursor.execute(sql)
for key in data[0]:
cur_ip = key.split(".")[3]
cursor.execute("""INSERT INTO %s VALUES (%s,%s)""" %(data[1],key,data[0][key]))
db.commit()
the problem is where I have %(data[1], key, data[0][key]) any ideas?
It's a little hard to analyse your problem when you don't post the actual error, and since we have to guess what your data actually is. But some general points as advise:
Using a dynamic table name is often not way DB-systems want to be used. Try thinking if the problem could be used by using a static table name and adding an additional key column to your table. Into that field you can put what you did now as a dynamic table name. This way the DB might be able to better optimize your queries, and your queries are less likely to get errors (no need to create extra tables on the fly for once, which is not a cheap thing to do. Also you would not have a need for dynamic DROP TABLE queries, which could be a security risk.
So my advice to solve your problem would be to actually work around it by trying to get rid of dynamic table names altogether.
Another problem you have is that you are using python string formatting and not parameters to the query itself. That is a security problem in itself (SQL-Injections), but also is the problem of your syntax error. When you use numbers, your expression evaluates to
INSERT INTO table_name VALUES (100, 200)
Which is valid SQL. But with strings you get
INSERT INTO table_name VALUES (Some Text, some more text)
which is not valid (since you have no quotes ' around the strings.
To get rid of your syntax problem and of the sql-injection-problem, don't add the values to the string, pass them as a list to execute():
cursor.execute("INSERT INTO table_name VALUES (%s,%s)", (key, data[0][key]))
If you must have a dynamic table name, put that in your query string first (e.g. with % formatting), and give the actual values for your query as parameters as above (since I cannot imagine that execute will accept the table name as a parameter).
To put it in some simple sample code. Right now you are trying to do it like this:
# don't do this, this won't even work!
table_name = 'some_table'
user_name = 'Peter Smith'
user_age = 47
query = "INSERT INTO %s VALUES (%s, %s)" % (table_name, user_name, user_age)
cursor.execute(query)
That creates query
INSERT INTO some_table VALUES (Peter Smith, 100)
Which cannot work, because of the unquoted string. So you needed to do:
# DON'T DO THIS, it's bad!
query = "INSERT INTO %s VALUES ('%s', %s)" % (table_name, user_name, user_age)
That's not a good idea, because you need to know where to put quotes and where not (which you will mess up at some point). Even worse, imagine a user named named Connor O'Neal. You would get a syntax error:
INSERT INTO some_table VALUES ('Connor O'Neal', 100)
(This is also the way sql-injections are used to crush your system / steal your data). So you would also need to take care of escaping the values that are strings. Getting more complicated.
Leave those problems to python and mysql, by passing the date (not the table name) as arguments to execute!
table_name = 'some_table'
user_name = 'Peter Smith'
user_age = 47
query = "INSERT INTO " + table_name + " VALUES (%s, %s)"
cursor.execute(query, (user_name, user_age))
This way you can even pass datetime objects directly. There are other ways to put the data than using %s, take a look at this examples http://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-execute.html (that is python3 used there, I don't know which you use - but except of the print statements it should work with python2 as well, I think).

Python cx_Oracle Update

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.)

Python pymysql INSERT INTO inserting empty values

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.

Categories