Update a PostgreSql table using a Python variable - python

I have the following table in my PostgreSql database with 1 row of data.
I want to update the value in the "diagnosis" column (currently 3) to another number. My python code is below:
Based on my code below, the "diagnosis" column should equal whatever number is assigned to the python diagnosis variable. In this case, the "diagnosis" column in my table should equal 5.
diagnosis = 5;
# eyeball
conn = psycopg2.connect("dbname=eyeballdbfinal user=postgres")
print ("Database opened successfully")
cur = conn.cursor()
cur.execute("UPDATE eyeballtables set DIAGNOSIS = diagnosis where id = 1") # fix this
conn.commit()
print("Total updated rows:", cur.rowcount)
But my SQL code inside my python is not working. Specifically, after running my python code above, my table should have 5 as the diagnosis. Instead, nothing changes. I think this part of the code DIAGNOSIS = diagnosis is not working.
What am I doing wrong?

Use the variable as a parameter:
cur.execute("UPDATE eyeballtables set DIAGNOSIS = %s where id = 1", (diagnosis,))
Read: Passing parameters to SQL queries

Related

Python MySQL search entire database for value

I have a GUI interacting with my database, and MySQL database has around 50 tables. I need to search each table for a value and return the field and key of the item in each table if it is found. I would like to search for partial matches. ex.( Search Value = "test", "Protest", "Test123" would be matches. Here is my attempt.
def searchdatabase(self, event):
print('Searching...')
self.connect_mysql() #Function to connect to database
d_tables = []
results_list = [] # I will store results here
s_string = "test" #Value I am searching
self.cursor.execute("USE db") # select the database
self.cursor.execute("SHOW TABLES")
for (table_name,) in self.cursor:
d_tables.append(table_name)
#Loop through tables list, get column name, and check if value is in the column
for table in d_tables:
#Get the columns
self.cursor.execute(f"SELECT * FROM `{table}` WHERE 1=0")
field_names = [i[0] for i in self.cursor.description]
#Find Value
for f_name in field_names:
print("RESULTS:", self.cursor.execute(f"SELECT * FROM `{table}` WHERE {f_name} LIKE {s_string}"))
print(table)
I get an error on print("RESULTS:", self.cursor.execute(f"SELECT * FROM `{table}` WHERE {f_name} LIKE {s_string}"))
Exception: (1054, "Unknown column 'test' in 'where clause'")
I use a similar insert query that works fine so I am not understanding what the issue is.
ex. insert_query = (f"INSERT INTO `{source_tbl}` ({query_columns}) VALUES ({query_placeholders})")
May be because of single quote you have missed while checking for some columns.
TRY :
print("RESULTS:", self.cursor.execute(f"SELECT * FROM `{table}` WHERE '{f_name}' LIKE '{s_string}'"))
Have a look -> here
Don’t insert user-provided data into SQL queries like this. It is begging for SQL injection attacks. Your database library will have a way of sending parameters to queries. Use that.
The whole design is fishy. Normally, there should be no need to look for a string across several columns of 50 different tables. Admittedly, sometimes you end up in these situations because of reasons outside your control.

can I get only the updated data from database instead of all the data

I am using sqlite3 in python 3 I want to get only the updated data from the database. what I mean by that can be explained as follows: the database already has 2 rows of data and I add 2 more rows of data. How can I read only the updated rows instead of total rows
Note: indexing may not help here because the no of rows updating will change.
def read_all():
cur = con.cursor()
cur.execute("SELECT * FROM CVT")
rows = cur.fetchall()
# print(rows[-1])
assert cur.rowcount == len(rows)
lastrowids = range(cur.lastrowid - cur.rowcount + 1, cur.lastrowid + 1)
print(lastrowids)
If you insert rows "one by one" like that
cursor.execute('INSERT INTO foo (xxxx) VALUES (xxxx)')
You then can retrieve the last inserted rows id :
last_inserted_id = cursor.lastrowid
BUT it will work ONLY if you insert a single row with execute. It will return None if you try to use it after a executemany.
If you are trying to get multiple ids of rows that were inserted at the same time see that answer that may help you.

Python and Pandas to Query API's and update DB

I've been querying a few API's with Python to individually create CSV's for a table.
I would like to try and instead of recreating the table each time, update the existing table with any new API data.
At the moment the way the Query is working, I have a table that looks like this,
From this I am taking the suburbs of each state and copying them into a csv for each different state.
Then using this script I am cleaning them into a list (the api needs the %20 for any spaces),
"%20"
#suburbs = ["want this", "want this (meh)", "this as well (nope)"]
suburb_cleaned = []
#dont_want = frozenset( ["(meh)", "(nope)"] )
for urb in suburbs:
cleaned_name = []
name_parts = urb.split()
for part in name_parts:
if part in dont_want:
continue
cleaned_name.append(part)
suburb_cleaned.append('%20'.join(cleaned_name))
Then taking the suburbs for each state and putting them into this API to return a csv,
timestr = time.strftime("%Y%m%d-%H%M%S")
Name = "price_data_NT"+timestr+".csv"
url_price = "http://mwap.com/api"
string = 'gxg&state='
api_results = {}
n = 0
y = 2
for urbs in suburb_cleaned:
url = url_price + urbs + string + "NT"
print(url)
print(urbs)
request = requests.get(url)
api_results[urbs] = pd.DataFrame(request.json())
n = n+1
if n == y:
dfs = pd.concat(api_results).reset_index(level=1, drop=True).rename_axis(
'key').reset_index().set_index(['key'])
dfs.to_csv(Name, sep='\t', encoding='utf-8')
y = y+2
continue
print("made it through"+urbs)
# print(request.json())
# print(api_results)
dfs = pd.concat(api_results).reset_index(level=1, drop=True).rename_axis(
'key').reset_index().set_index(['key'])
dfs.to_csv(Name, sep='\t', encoding='utf-8')
Then adding the states manually in excel, and combining and cleaning the suburb names.
# use pd.concat
df = pd.concat([act, vic,nsw,SA,QLD,WA]).reset_index().set_index(['key']).rename_axis('suburb').reset_index().set_index(['state'])
# apply lambda to clean the %20
f = lambda s: s.replace('%20', ' ')
df['suburb'] = df['suburb'].apply(f)
and then finally inserting it into a db
engine = create_engine('mysql://username:password#localhost/dbname')
with engine.connect() as conn, conn.begin():
df.to_sql('Price_historic', conn, if_exists='replace',index=False)
Leading this this sort of output
Now, this is a hek of a process. I would love to simplify it and make the database only update the values that are needed from the API, and not have this much complexity in getting the data.
Would love some helpful tips on achieving this goal - I'm thinking I could do an update on the mysql database instead of insert or something? and with the querying of the API, I feel like I'm overcomplicating it.
Thanks!
I don't see any reason why you would be creating CSV files in this process. It sounds like you can just query the data and then load it into a MySql table directly. You say that you are adding the states manually in excel? Is that data not available through your prior api calls? If not, could you find that information and save it to a CSV, so you can automate that step by loading it into a table and having python look up the values for you?
Generally, you wouldn't want to overwrite the mysql table every time. When you have a table, you can identify the column or columns that uniquely identify a specific record, then create a UNIQUE INDEX for them. For example if your street and price values designate a unique entry, then in mysql you could run:
ALTER TABLE `Price_historic` ADD UNIQUE INDEX(street, price);
After this, your table will not allow duplicate records based on those values. Then, instead of creating a new table every time, you can insert your data into the existing table, with instructions to either update or ignore when you encounter a duplicate. For example:
final_str = "INSERT INTO Price_historic (state, suburb, property_price_id, type, street, price, date) " \
"VALUES (%s, %s, %s, %s, %s, %s, %s, %s) " \
"ON DUPLICATE KEY UPDATE " \
"state = VALUES(state), date = VALUES(date)"
con = pdb.connect(db_host, db_user, db_pass, db_name)
with con:
try:
cur = con.cursor()
cur.executemany(final_str, insert_list)
If the setup you are trying is something for longer term , I would suggest running 2 diff processes in parallel-
Process 1:
Query API 1, obtain required data and insert into DB table, with binary / bit flag that would specify only API 1 has been called.
Process 2:
Run query on DB to obtain all records needed for API call 2 based on binary/bit flag that we set in process 1--> For corresponding data run call 2 and update data back to DB table based on primary Key
Database : I would suggest adding Primary Key as well as [Bit Flag][1] that gives status of different API call statuses. Bit Flag also helps you
- in case you want to double confirm if specific API call has been made for specific record not.
- Expand your project to additional API calls and can still track status of each API call at record level
[1]: Bit Flags: https://docs.oracle.com/cd/B28359_01/server.111/b28286/functions014.htm#SQLRF00612

How to stream/print the several last appended data from a table in SQL Server using python?

I have a table in my SQL Server that is being updated every minute.
Currently, I get the data from my table using this lines of code:
conn = pymssql.connect(server, user, password, "tempdb")
def print_table():
cursor = conn.cursor(as_dict=True)
cursor.execute('SELECT * FROM EmotionDisturbances WHERE name=%s', 'John Doe')
for row in cursor:
#Show the data:
print("rate=%d, emotion=%s" % (row['rate'], row['emotion']))
conn.close()
In my application, I run this the function every 10 seconds.
How do I update the function so that I only print the last appended data from my table?
Thanks
Assuming you have an auto-incrementing index in column id you'd do:
SELECT * FROM EmotionDisturbances WHERE name = % ORDER BY id DESC LIMIT 1
EDIT: If you want all data that was added after a certain time, then you'll need to migrate your schema to have a created date column if it doesn't have one already, then you can do:
SELECT *
FROM EmotionDisturbances
WHERE name = % AND created >= DATEADD(second, -10, GETDATE())
This would get all of the records created over the last 10 seconds, since you said this function runs every 10 seconds.

looking for SQL insert syntax for informix via python informixdb

Cant find the correct syntax for INSERT query with python informixdb
python 2.6.6
python INFORMIXDB version 2.5
driver name : IBM Informix-ESQL
driver version : 3.50.FC8
on debian squeeze
here's the doc - http://informixdb.sourceforge.net/manual.html#binding-parameters
>>> cursor.execute('INSERT INTO names VALUES(:first,:last,:age)',
... dict(first='some', last='body', age=56) )
So i tried for example
cursor.execute('INSERT INTO transit_auftrag_i VALUES(:auftragskey,:transitkunde,:status)',dict(auftragskey='erII',transitkunde='DMIeLE',status='OK') )
this is what i get in this example
<class '_informixdb.ProgrammingError'>
('PREPARE', -236, [{'message': 'Insert value list does not match column list', 'sqlstate': '21S01'}])
<class '_informixdb.ProgrammingError'>
('DESCRIBE', -410, [{'message': 'Syntax error or access violation in PREPARE or EXECUTE IMMEDIATE', 'sqlstate': '37000'}])
Segmentation fault
any hints what i could try please?
UPDATE: informix 11.50.xC8
UPDATE
thanks so far. I do the following query now which runs without errors, but also with no message from the cursor and it does not insert anything. If you have a suggestion it would be great.
cursor.execute("INSERT INTO transit_auftrag_i (auftragskey,transitkunde,status) VALUES (:a,:b,:c)", dict(a='A',b='B',c='C') )
You should list the columns explicitely that you want to populate:
INSERT INTO names (firstname, lastname, age) VALUES (:first,:last,:age)
Apperently your table has more columns than you supply, or they are in a different order.
Not stating the columns for an INSERT statement is a bad programming habit, that you should get rid off as quick as possible
If your database table has a lot of columns, consider also creating a class containing enumerated types, and refer to the columns by name. At the beginning of our AMR project 1 1/2 years ago, I tried referring to columns using just index numbers on a 20+ column table (data input from a vendor); it was a disaster, until I created a class.
The following is for Python 2.6.5.
premid = mapErtToPremId(ins_row[d.DeviceID], ins_row[d.DeviceType], ins_row[d.ChannelNumber], db)
class drIdx():
def __init__(self):
self.MeterID = 0
self.Reading = 1
self.ReadingDateTime = 2
self.Account = 3
self.CustomerLN = 4
self.CustomerFN = 5
self.DeviceID = 6
self.DeviceType = 7
self.ChannelNumber = 8
self.DecodeType = 9
self.LoadDateLocal = 10
self.PremiseID = 11

Categories

Resources