Referencing row values in pyodbc when column name contains dashes (hyphens) - python

I am new to python and pyodbc
I try to print the first a row from a table from a progress openedge database. (Windows 7) Here is the code block that is not running:
cursor.execute("select my-nr, my-dt-my from mytable")
row = cursor.fetchone()
print(row.my-nr, row.my-dt-my)
This gives errors undefined name: 'nr'
undefined name 'dt'
undefined name 'my'
I guess it has something to do with the minus - symbols behind the dot . in print(row.my-nr, row.my-dt-my)
It was easy to print out the table names and column names from the database earlier but for some reason printing out rows is harder.
Any ideas how to get the rows printed?

pyodbc allows us to reference values in a pyodbc.Row object using the form row.column_name provided that the column names are legal Python identifiers. So, for example, we can do something like
row = crsr.fetchone()
print(row.city)
to print the value of the "city" column. Unfortunately, my-nr is not a legal Python identifier so if we try to print the value of the "my-nr" column using ...
row = crsr.fetchone()
print(row.my-nr) # error
... Python parses that as "row.my minus nr" where row.my would be interpreted as a column in the Row object and nr would be interpreted as a Python variable.
To work around the issue we can grab a list of the column names, merge those names with the row values into a dictionary, and then refer to the values in the dictionary:
crsr.execute(sql)
col_names = [x[0] for x in crsr.description]
row = crsr.fetchone()
row_as_dict = dict(zip(col_names, row))
print(row_as_dict['my-nr']) # no error

The most simple solution I can think of is this. First, columns containing hyphens need to be quoted in OpenEdge (see here). Second, you can alias the columns so they can be referenced as valid Python attributes. You'll need to do something like this:
cursor.execute('select "my-nr" as mynr, "my-dt-my" as mydtmy from mytable')
row = cursor.fetchone()
print(row.mynr, row.mydtmy)
Good luck!

I beleive that you need to change the variable names of the database, make sure they don't contain any '-' characters.
Variables can not contain characters reserved by python. For example you have to avoid hyphens(-), exclamation marks (!), colons (:) and so on.
According to this answer it seems like underscore (_) is the only character allowed in variable names.

Related

different output from pandas iterrows if .csv column headed "name" than other text

i'm a beginner using pandas to look at a csv. i'm using .iterrows() to see if a given record matches today's date, so far so good. however when calling (row.name) for a .csv with a column headed 'name' i get different output than if i rename the column and edit the (row."column-heading") to match. i can call it anything but "name" and get the right output. i tried (row.notthename) (row.fish) and (row.thisisodd) - which all worked fine - before coming here.
if the first colmumn in birthdays.csv is "name" and i call print(row.name) it returns "2". if the first column is "notthename" and i call print(row.notthename) it returns the relevant name. what gives? i don't understand why arbitrarily renaming the column and the function call is yielding different output?
eg case A: column named "name"
birthdays.csv:
name,email,year,month,day
a test name,test#email.com,1961,12,21
testerito,blagh#sdgdg.com,1985,02,23
testeroonie,sihgfdb#sidkghsb.com,2022,01,17
data = pandas.read_csv("birthdays.csv")
for (index, row) in data.iterrows():
if (dt.datetime.now()).month == row.month and (dt.datetime.now()).day == row.day:
print(row.name)
outputs "2"
whereas case B: column named "notthename"
data = pandas.read_csv("birthdays.csv")
for (index, row) in data.iterrows():
if (dt.datetime.now()).month == row.month and (dt.datetime.now()).day == row.day:
print(row.notthename)
outputs "testeroonie"
i'm missing something.... is there some special handling of "name" going on?
thanks for helping me learn!
This happens because DataFrame.iterrows returns a Series object, and the Series object has a built-in property called name. This is why using the object shortcut for column names, although convenient, can be dangerous. The dictionary notation doesn't have this issue:
print(row['name'])

Creating a table in MariaDB using a list of column names in Python

I am trying to create a table in mariadb using python. I have all the column names stored in a list as shown below.
collist = ['RR', 'ABPm', 'ABPs', 'ABPd', 'HR', 'SPO']
This is just the sample list. Actual list has 200 items in the list. I am trying to create a table using the above collist elements as columns and the datatype for the columns is VARCHAR.
This is the code I am using to create a table
for p in collist:
cur.execute('CREATE TABLE IF NOT EXISTS table1 ({} VARCHAR(45))'.format(p)
The above code is executing but only the first element of the list is being added as a column in the table and I cannot see the remaining elements. I'd really appreciate if I can get a help with this.
You can build the string in 3 parts and then .join() those together. The middle portion is the column definitions, joining each of the item in the original list. This doesn't seem particularly healthy; both in the number of columns and the fact that everything is VARCHAR(45) but that's your decision:
collist = ['RR', 'ABPm', 'ABPs', 'ABPd', 'HR', 'SPO']
query = ''.join(["(CREATE TABLE IF NOT EXISTS table1 ",
' VARCHAR(45), '.join(collist),
' VARCHAR(45))'])
Because we used join, you need to specify the last column type separately (the third item in the list) to correctly close the query.
NOTE: If the input data comes from user input then this would be susceptible to SQL injection since you are just formatting unknown strings in, to be executed. I am assuming the list of column names is internal to your program.

Error while adding columns to SQLite3 database table using python loop

I am trying to create a table in SQLite database using a list of items in python but while creating a table it is giving me an operational error.
I am using a python for loop to use this list items as column headers. The loop was working fine till list item 'QT' and after that it is breaking and giving me the error.
col_names = [
"ABPs",
"ABPd",
"ABPm",
"ARTs",
"ARTd",
"ARTm",
"AoS",
"AoD",
"AoM",
"UAPs",
"UAPd",
"UAPm",
"P1s",
"P1d",
"P1m",
"NBPs",
"NBPd",
"NBPm",
"P_1d",
"P_1m",
"PVC",
"QT",
"QT-HR",
"QTc",
"ST-I",
"ST-II",
"ST-III",
"ST-aVR",
"ST-aVF",
"ST-aVL",
"ST-MCL",
"ST-V1",
"ST-V2",
"dQTc",
"ST-V3",
"ST-V4",
"ST-V5",
"ST-V6",
]
cur.execute("""CREATE TABLE CICU2 (datetime DATETIME)""")
for colname in col_names:
cur.execute("""ALTER TABLE CICU2 ADD COLUMN """ + colname + """ TEXT""")
Error : near "-": syntax error.
- is not permitted in unescaped column names; you are asking SQLite to subtract one column name from another. You must use proper quoting if you want to use any non-standard characters in a column name.
The standard method of quoting a column name is to use double quotes; any existing double quotes in a column name can be replaced with doubled double quotes:
cur.execute('ALTER TABLE CICU2 ADD COLUMN "{}" TEXT'.format(colname.replace('"', '""'))
I used a format string to insert the column name into the query, which is easier to read for humans. The {} part is replaced by the value of the first argument to the str.format() method.

SQL syntax error with psycopg2 (python)

So I'm attempting to write my own sqlite3 to postgresql migration script, which takes all the tables from one database to another.
I'm currently seeing the following syntax error:
ERROR: syntax error at or near "'name'"
LINE 1: UPDATE django_site SET ('name', 'domain')=('127.0.0.1:8080',...
^
It's not quite liking ('name', 'domain') ... I'm perhaps thinking there's something subtle I'm missing...
('name', 'domain') is generated from the following line of code:
col = tuple([desc[0] for desc in self.cur_sql3.description])
i.e., taking all of the column names as a generated list then converting to tuple type.
And the SQL query is currently being built as such:
cur_psql.execute("UPDATE {0} SET {1}={2} WHERE id={3}".format(table[0], col[1:], row[1:], col[0]))
table[0] is the table name, col[1:] is everything but the primary id key, row[1:] are all the row values minus the primary key, and col[0] is the primary key value, e.g., 1,2,3,4 or 5 etc
Any obvious tips to avoid this issue?
You'll need to split this into separate SQL statements or you'll need to do some kind of looping over your column value pairs. I would need more information to write the corrected Python code, but your SQL should look something like this:
UPDATE table SET col = val WHERE id = id_val
You're doing something like:
UPDATE table SET ('col1', 'col2') = ('val1', 'val2')
If you want to update multiple columns in one statement, you'd do this:
UPDATE table SET col1 = val1, col2 = val2 WHERE id = id_val
Keep in mind you'll need to escape your values if they're character columns (but not if they're numeric), like so:
UPDATE table SET col1 = 'character value', col2 = 123 WHERE id = 1
Ultimately, this should be accomplished with bind variables rather than string formatting, as string formatting can expose your code to SQL injection attacks (might not be a concern if this is strictly a utility script that you're running yourself but it's a good habit to get into regardless). You can find the documentation for bind variables in psycopg2 here: http://initd.org/psycopg/docs/usage.html#query-parameters
Following my advice above would result in something like this:
set_clauses = ",".join(["{} = %s".format(col) for col in col[1:]])
query = "update {} set {} where id = {}".format(table[0], set_clauses, row[0])
cur_psql.execute(query, row[1:])

sql output in treeview columns using tkinter module in python

i am trying to output 2 different returns from sql queries in to the respective columns in a treeview widget using tkinter module in python 3.4 When i run command defined below the first column prints all the entries correctly but the name column prints the name of the first result in all rows instead of name per respective row. Any ideas on what im doing wrong?
def refreshtrade():
for i in treeview.get_children():
treeview.delete(i)
#order number
refreshtradein = conn.cursor()
refreshtradein.execute("SELECT increment_id FROM mg_ikantam_buyback_order")
#first name
names =conn.cursor()
names.execute("SELECT customer_firstname FROM mg_ikantam_buyback_order")# WHERE increment_id = 'buyback-%s'" %(tradeinentryfield.get() ))
for n in names:
for r in refreshtradein:
treeview.insert('',0,r,text = r, values=(n,'Mercedes', 'Purchased', '8-34-15'))
refreshtradein.close()
conn.close()
Why are you using two different cursors and consequently two nested for loops? Are you aware how nested for loops are evaluated?
querycursor = conn.cursor()
querycursor.execute(SELECT increment_id, customer_firstname FROM mg_ikantam_buyback_order)
for row in querycursor:
print(row[0])
print(row[1])
Oh and regarding your where clause. Don't ever do parameter substitution like that. It is great security risk
See here how to do it correctly

Categories

Resources