I try to make a line graph with python and the graph only appears a little in the end of the canvas in the GUI.
import sqlite3
###----------------Connecting to the database-------------#####
DB = sqlite3.connect ("personal_project.db")
CURSOR = DB.cursor()
###----------------create the SQL command to create the table and save data-------------######
COMMAND1 = """CREATE TABLE IF NOT EXISTS
balance (
UserID INTEGER PRIMARY KEY,
Date TEXT,
Amount TEXT,
Descriotion)"""
CURSOR.execute(COMMAND1)
from tkinter import *
from tkinter import messagebox
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
###----------------Create the window-------------#####
main_WINDOW = Tk()
main_WINDOW.title("Study App")
main_WINDOW.geometry("1940x1080")#width*length
main_WINDOW.configure(bg="#ffffff")
###------Show Information Using Graph-------###
graquery = '''SELECT Date, Amount FROM balance'''
CURSOR.execute(graquery)
graresults = CURSOR.fetchall()
Date = [result[0] for result in graresults]
Amount = [result[1] for result in graresults]
figure = plt.figure()
plt.plot(Date, Amount)
plt.xlabel('Date')
plt.ylabel('Amount')
plt.title('Balance graph Graph')
gracanvas = Canvas(main_WINDOW, width=1070, height=452)
gracanvas.pack()
gracanvas.place(x=356, y=270)
figure_canvas = FigureCanvasTkAgg(figure, gracanvas)
gracanvas.create_window(0,0,window=figure_canvas.get_tk_widget())
My company gets a few flat files each week that needs to be uploaded into our database. These are usually split off into two separate tables depending on the naming conventions of the file. The source of the files are consistent and the columns are validated before running the python script. Attached is what the code currently looks like
import glob
import pandas as pd
import numpy
import pyodbc as dbc
def uploadPerson(filename):
conn = dbc.connect('Driver={SQL Server Native Client 11.0};Server=SERVERNAME;Database=DATABASENAME;Trusted_Connection=yes;')
df = pd.read_excel(filename)
cursor = conn.cursor()
output = df.values.tolist()
cursor.executemany("INSERT INTO DATABASENAME.dbo.Person VALUES(?,?,?,?)", output)
conn.commit()
print('{0} imported - Rows: {1}, Columns: {2}'.format(filename,len(df),len(df.columns)))
cursor.close()
conn.close()
def uploadCustomer(filename):
conn = dbc.connect('Driver={SQL Server Native Client 11.0};Server=SERVERNAME;Database=DATABASENAME;Trusted_Connection=yes;')
df = pd.read_excel(filename)
cursor = conn.cursor()
output = df.values.tolist()
cursor.executemany("INSERT INTO DATABASENAME.dbo.Customer VALUES(?,?,?,?,?,?)", output)
conn.commit()
print('{0} imported - Rows: {1}, Columns: {2}'.format(filename,len(df),len(df.columns)))
cursor.close()
conn.close()
def main():
print('Starting Program')
for filename in glob.glob('*.xlsx'):
if 'Person' in filename:
uploadPerson(filename)
elif 'Customer' in filename:
uploadCustomer(filename)
else:
print('{0} cannot be imported, incorrect name'.format(filename))
print('Program Finished')
My questions are:
Is it better to implicitly declare the connection/close to the database within each function or state it once in the main function and only perform commits in each function? Not sure how much of a performance hit this takes and was curious what is the best practice using pyodbc.
If multiple queries are going to be called to different, is it best to initialize/close the cursor?
Since the functions basically handle the same way aside from the SQL would it be better to statically define the sql with if/else and just have one upload function?
With the refactored code, would this be more pythonic and efficient with runtime?
import glob
import pandas as pd
import numpy
import pyodbc as dbc
def uploadPerson(filename,conn,cursor):
df = pd.read_excel(filename)
output = df.values.tolist()
cursor.executemany("INSERT INTO DATABASENAME.dbo.Person VALUES(?,?,?,?)", output)
conn.commit()
print('{0} imported - Rows: {1}, Columns: {2}'.format(filename,len(df),len(df.columns)))
def uploadCustomer(filename,conn,curosr):
df = pd.read_excel(filename)
output = df.values.tolist()
cursor.executemany("INSERT INTO DATABASENAME.dbo.Customer VALUES(?,?,?,?,?,?)", output)
conn.commit()
print('{0} imported - Rows: {1}, Columns: {2}'.format(filename,len(df),len(df.columns)))
def main():
print('Starting Program')
conn = dbc.connect('Driver={SQL Server Native Client 11.0};Server=SERVERNAME;Database=DATABASENAME;Trusted_Connection=yes;')
cursor = conn.cursor()
for filename in glob.glob('*.xlsx'):
if 'Person' in filename:
uploadPerson(filename, conn, cursor)
elif 'Customer' in filename:
uploadCustomer(filename, conn, cursor)
else:
print('{0} cannot be imported, incorrect name'.format(filename))
cursor.close()
conn.close()
print('Program Finished')
A bit newer to programming with pyodbc so best practices would be appreciated!
Consider encapsulating your methods inside a class object which opens connection once and re-uses cursor multiple times and on deletion of object closes the cursor and connection.
import glob
import pandas as pd
import numpy as np
import pyodbc as dbc
class DataBaseAPI(xl_files):
def __init__(self):
self.glob_files = glob.glob(xl_files)
self.success_results_msg = '{0} imported in table {1} - Rows: {2}, Columns: {3}'
self.failed_import_msg = '{0} cannot be imported, incorrect name'
# INITIALIZE DB OBJECTS
conn_str = 'Driver={SQL Server Native Client 11.0};'
'Server=SERVERNAME;Database=DATABASENAME;'
'Trusted_Connection=yes;'
self.conn = dbc.connect(conn_str)
self.cursor = self.conn.cursor()
def processFiles():
for filename in self.glob_files:
if 'Person' in filename:
self.filename = filename
self.uploadPerson()
elif 'Customer' in filename:
self.filename = filename
self.uploadCustomer()
else:
print(self.failed_import_msg.format(filename))
def uploadPerson(self):
df = pd.read_excel(self.filename)
output = df.to_numpy().tolist()
self.cursor.executemany("INSERT INTO DATABASENAME.dbo.Person VALUES(?,?,?,?)", output)
self.conn.commit()
print(self.success_results_msg.format(filename,'Person',len(df),len(df.columns)))
def uploadCustomer(self):
df = pd.read_excel(self.filename)
output = df.to_numpy().tolist()
self.cursor.executemany("INSERT INTO DATABASENAME.dbo.Customer VALUES(?,?,?,?,?,?)", output)
self.conn.commit()
print(self.success_results_msg.format(filename,'Customer',len(df),len(df.columns)))
def __del__(self):
# CLOSE DB OBJECTS
self.cursor.close()
self.conn.close()
obj = DataBaseAPI('*.xlsx')
obj.processFiles()
del obj
Alternatively, use the __enter__ and __exit__ methods to run your class object in a context manager:
class DataBaseAPI(xl_files):
def __init__(self):
self.glob_files = glob.glob(xl_files)
self.success_results_msg = '{0} imported in table {1} - Rows: {2}, Columns: {3}'
self.failed_import_msg = '{0} cannot be imported, incorrect name'
def __enter__(self):
# INITIALIZE DB OBJECTS
conn_str = 'Driver={SQL Server Native Client 11.0};'
'Server=SERVERNAME;Database=DATABASENAME;'
'Trusted_Connection=yes;'
self.conn = dbc.connect(conn_str)
self.cursor = self.conn.cursor()
return self # IMPORTANT TO ADD
...
def __exit__(self, exception_type, exception_val, trace):
# CLOSE DB OBJECTS
self.cursor.close()
self.conn.close()
with DataBaseAPI('*.xlsx') as obj:
obj.processFiles()
I have an issue that I can´t see clearly and I ask for help here. I don´t know why when I run my code the rows print twice instead of just one. I have 5 rows in my database and when I execute the code it returns 10 rows, the first five and then the five repeated.
from tkinter import *
from tkinter import ttk
from PIL import ImageTk, Image
import sqlite3
class fed:
db_name = 'database.db'
def __init__(self, window):
self.wind = window
self.wind.title('ligth')
self.wind.iconbitmap('doggy.ico')
self.wind.geometry("500x200")
self.get_name()
def run_query(self, query, parameters = ()):
with sqlite3.connect(self.db_name) as conn:
cursor = conn.cursor()
result = cursor.execute(query, parameters)
conn.commit()
return result
def get_name(self):
query = 'SELECT * FROM name'
db_rows = self.run_query(query)
for row in db_rows:
print(row)
if __name__ == '__main__':
window = Tk()
fed(window)
application = fed(window)
window.mainloop()
You are running the class twice, on the 3rd and 2nd to last lines. Remove one of your fed(window) calls.
I want to create a simple chart with these library written below. Here is how I did:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import MySQLdb
def mysql_select_all():
conn = MySQLdb.connect(host='localhost',
user='root',
passwd='password',
db='databse')
cursor = conn.cursor()
sql = "SELECT price,size1 FROM 008_table"
cursor.execute(sql)
result = cursor.fetchall()
df = pd.DataFrame(list(sql),columns=["price","size1"])
x = df.price
y = df.size1
plt.title("Table", fontsize="24")
plt.scatter(x, y, s=100)
plt.xlabel("Size1")
plt.ylabel("Price")
plt.tick_params(axis='both',which='major',labelsize=14)
cursor.close()
print("Start")
mysql_select_all()
print("End")
I got the Value Error with this code, where should I fix this code ?
By:
df = pd.DataFrame(list(sql),columns=["price","size1"])
did you mean to type:
df = pd.DataFrame(list(result),columns=["price","size1"])
?
from tkinter import *
import tkinter as tk
import pyodbc
root1 = tk.Tk()
label1 = tk.Label(root1, text='product A')
input1 = StringVar()
entry1 = tk.Entry(root1,textvariable=input1)
label1.pack(side = tk.TOP)
entry1.pack()
buttonstr = tk.StringVar()
db = r"C:\Users\Goutham\Documents\keshav\testdb.accdb"
def odbc():
'''
connects with odbc
'''
constr = 'Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq=' + db
conn = pyodbc.connect(constr, autocommit=True)
cur = conn.cursor()
check=input1.get()
strsql = "select * from student where SName=%s"%(check)
cur.execute(strsql)
results = cur.fetchall()
print (results,check)
conn.close()
buttonA = tk.Button(text = "hello", command = odbc)
buttonA.pack()
I need this code to get input,store it in the variable -'check' and compare it with the values in the database using a SQL query.The matching values from the database are then displayed.
There seems to be a problem in the implementation of the SQL query.'check' stores the value of the input. The SQL query does not work properly and causes errors.
Please help.
Thank you.
You need to single quote the parameter to the WHERE clause:
strsql = "select * from student where SName='%s'" % (check,)
But be careful with building clauses like this (using string formatting), you run the risk of SQL injection. You should pass parameters instead:
strsql = "select * from student where SName=?"
cur.execute(strsql, (check,))