Select statement in sqlite3(Python) without pacemaker is working fine but is behaving odd with the pacemaker(?)
In the below code when I'm using "table_column_name" in the select I am getting all the items in my list populated in my list box. but when I am passing it as tuple to select statement with the help of pacemaker my list bosx has only one entry i.e "table_column_name".
class ListObj(tkinter.Listbox):
def __init__(self, window, cname, r, c, rs, cs, sticky, bg,
padx=5, pady=5, ipadx=0, ipady=0, **kwargs):
self = tkinter.Listbox(window)
self.grid(row=r, column=c, rowspan=rs, columnspan=cs,
sticky=sticky, padx=padx, pady=pady,
ipadx=ipadx, ipady=ipady)
List = cursor.execute(f"SELECT DISTINCT ? FROM juke_box",
(cname,))
for x in List:
print(x)
self.insert(tkinter.END, x)
list_box= ListObj(root, 'table_column_name',1,0,2,1,'nsew', 'sky blue')
my expected outcome is that I should get all the items in the column name passed as tuple should populate in the tk list.
List = cursor.execute(f"SELECT DISTINCT ? FROM juke_box",
(cname,))
Looks like you're trying to pass a column name as a bound parameter. You can't do that; table and column names have to be present in the SQL statement when it's compiled, not passed at execution time. The cname variable is being bound as a string, and that string returned. Because it's a SELECT DISTINCT, and every row of the table ends up selecting the same 'table_column_name' string, only one row with that value is being returned. That whole query basically can be reduced to SELECT ? where the question mark is replaced by the string in cname.
Related
By selecting an item in the combobox, I would like to retrieve the database row that has the same name selected by the combobox in one of the fields.
For example, if in the combobox there is Tokyo, Madrid, London, Paris (obtained from the "example" column of the database) and I select Tokyo, I would like the row that has the text "Tokyo" in the "example" column to be searched in the database table. Then print the row separately.
I get the error when I try and retrieve and print the data:
TypeError: 'NoneType' object is not subscriptable
While tweaking the code a bit and trying to fix it, I no longer get the error, but the variables are printed as None, None, None, None.
I don't need the function ad i don't need a button. I would simply like that by selecting the combobox, the variables are printed.
Can anyone help me? Thank you
import sqlite3
from tkinter import ttk
import tkinter as tk
root = tk.Tk()
root.geometry('400x400')
root.config(bg="gray")
root.state("normal")
conn = sqlite3.connect('....')
cursor = conn.cursor()
def view_combobox():
cursor.execute('SELECT example FROM material LIMIT 2 OFFSET 2')
values = [row[0] for row in cursor]
return values
example=ttk.Combobox(root, width = 21)
example.place(x=10, y=10)
example.set("Select")
example['value'] = view_combobox()
select_example__button3 = example.get()
#################################################
#PROBLEM IS HERE
if select_example__button3:
cursor.execute('SELECT a, b, c, d FROM material WHERE example=?', (select_example__button3,))
value = cursor.fetchone()
print(value[0], value[1], value[2], value[3], value[4])
Database
CREATE TABLE "material" (
"id" INTEGER,
"a" INTEGER,
"b" INTEGER,
"c" INTEGER,
"d" INTEGER,
"example" TEXT,
PRIMARY KEY("id")
NOTE: I have tested that if I insert the condition inside a function and then call the function with a button, I no longer receive the error and the variables are printed correctly. But it was just a test, I DON'T NEED THE FUNCTION, AND I DON'T NEED A BUTTON. I would simply like that by selecting the combobox, the variables are printed
Have you checked the value return from cursor.fetchone(). If due to any reason if it returns empty resultset it returns None. So check the value obtained from cursor.fetchone() if it is not None then only print the value as
cursor.execute('SELECT a, b, c, d FROM material WHERE example=?', (select_example__button3,))
value = cursor.fetchone()
if value is not None:
print(value[0], value[1], value[2], value[3], value[4])
The error TypeError: 'NoneType' object is not subscriptable is telling you that you're trying to use a subscript on a variable that has the value None.
In your case it is the var variable. It is None because you are calling cursor.execute about a millisecond after creating the combobox. The user won't have seen the combobox much less had a chance to pick a value from it. Therefore, the value is going to be what you set it a few statements prior to the empty string and thus, the SQL statement won't find any matches.
I would simply like that by selecting the combobox, the variables are printed
To run a function when a combobox is selected you can bind to the <<ComboboxSelected>> event. It might look something like this:
def select_example(event):
selected_value = example.get()
cursor.execute('SELECT a, b, c, d FROM material WHERE example=?', (selected_value,))
value = cursor.fetchone()
if value:
print(value[0], value[1], value[2], value[3], value[4])
example.bind("<<ComboboxSelected>>", select_example)
If in the combo_Nations combobox I select a specific Country (the country name is extracted from the "All_Nations" table in the "Nations_name" column), I would like to get the corresponding ID_Nations of the respective selected country (ID_Nations is found in the same table "All_Nations"). The ID will be automatically inserted in another table of the database together with other fields, after clicking on the "Add" button with the function def_add.
(If you are wondering why I need to automatically insert the ID_Nation from another table, the reason is that I need it for relational purposes for a Foreign Key)
So I would like to take this data circled in red from the screenshot (I cannot attach images here): screenshot. Basically the table is this:
CREATE TABLE "All_Nations" (
"ID_Nations" INTEGER, >>> example: 453
"Nations_name" INTEGER, >>> example: England
PRIMARY KEY("ID_Nations" AUTOINCREMENT)
);
So the combobox combo_Nations with the def combo_nations function fetches Nations_name only. While def id_nations should extract ID_Nations corresponding to the selected Nation from the combobox. EXAMPLE: For example, if I select England in the combobox, id_nations should automatically save me 453. The two data will be saved in a new table thanks to the function def add () (I only wrote part of this code so as not to dwell on it, showing you the minimum to understand what I serves, because it works correctly). The new table will save a row in which there will be: ID, Nations_name, ID_Nations, other data of various kinds.
The error I get is this TypeError: 'list' object is not callable, to be precise this is it:
db.insert(nations.get(),.....other data .get(), id_campionati_value())
TypeError: 'list' object is not callable
I don't know if I wrote the def id_nations function incorrectly, if the problem is in db.insert or if the problem is both
HERE'S THE CODE. There is some problem in the def id_nations function I created:
def id_nations():
nations = combo_Nations.get()
cursor.execute('SELECT ID_Nations FROM All_Nations WHERE Nations_name=?',(nations,))
result = cursor.fetchone()
return result
#this is ok. no problem
def combo_nations():
campionato = combo_Nations.get()
cursor.execute('SELECT Nations_name FROM All_Nations')
result=[row[0] for row in cursor]
return result
#Combobox Nations
lbl_Nations = Label(root, text="Nations", font=("Calibri", 11), bg="#E95420", fg="white")
lbl_Nations.place(x=6, y=60)
combo_Nations = ttk.Combobox(root, font=("Calibri", 11), width=30, textvariable=nations, state="readonly")
combo_Nations.place(x=180, y=60)
combo_Nations.set("Select")
combo_Nations['values'] = combo_nations()
combo_Nations.bind('<<ComboboxSelected>>', combo_city)
The data will be saved here (everything works fine):
def add():
id_campionati_value=id_campionati()
db.insert(nations.get(),.....other data .get(), id_campionati_value())
messagebox.showinfo("Success", "Record Inserted")
clearAll()
dispalyAll()
Theoretically I understand what the problem is, but I don't know how to solve it. I'm just starting out with Python. Can you show me the solution in the answer? Thanks
P.S: I removed unnecessary parts of code so as not to lengthen the question, but there is everything you need to understand. Thanks
UPDATE
Rest of the code to insert data into the database. I write it in a somewhat confusing way because I have two files (main.py and db.py) and the code is split. If I write all the code of the two files it is too long.
def getData(event):
selected_row = tv.focus()
data = tv.item(selected_row)
global row
row = data["values"]
#print(row)
nations.set(row[1])
....
id_nations.set(row[10])
# Insert Function
def insert(self, nations,....., id_nations):
self.cur.execute("insert into All_Nations values (NULL,?,?,?,?,?,?,?,?,?,?)",
(nations,..., id_nations))
self.con.commit()
Based on the error, id_campionati_value is a list. When you do id_campionati_value() you're calling the list, and as the error says, you can't call the list.
Since you seem to need a single value, you first need to define id_nations to return the id rather than a list. It would look something like in the following example, returning the first column of the matching row.
I would also suggest renaming the function to make it more clear that it's fetching something from the database:
def get_id_nations():
nations = combo_Nations.get()
cursor.execute('SELECT ID_Nations FROM All_Nations WHERE Nations_name=?',(nations,))
result = cursor.fetchone()
return result[0]
Then, you can use this value when calling db.insert:
id_nations = get_id_nations()
db.insert(nations.get(),.....other data .get(), id_nations)
def get_info(search_by=input("Search by: "), value=input("Value: ")):
search = [
(f"{str(search_by)}", f"{str(value)}")
]
items = c.fetchall()
c.execute("SELECT * FROM credentials WHERE (?) LIKE '(?)'", (search,))
print(f"{item[0]}", f"{item[1]}", f"{item[2]}", f"{item[3]}")
conn.commit()
conn.close()
get_info()
I can't understand why I get this error. I'm trying to make the user choose what they want to search by and the value. (i.e search by "service", value "delivery".
There are several problems here.
You can't use a placeholder for a column name. It can only be used for expressions, and the substitution will be the literal value that comes from the parameter list. If you have a variable column name you need to use ordinary string formatting; you should have a white-list to prevent SQL injection.
Placeholders aren't replaced inside quotes.
You have your values nested too deeply. The second argument to c.execute() should be an iterable, and each element fills in one placeholder. search is a list of a tuple, and then you put it inside another tuple when you write (search,). So the values are nested 2 levels deep instead of being in the tuple argument.
Default values of a function should not be calls to input(). The default values are evaluated when the function is defined, not when it's called. So this will ask you for the inputs when you load the script, and use those same values as defaults every time the function is called.
You call c.fetchall() before you execute the query.
You're missing the for item in items: loop.
conn.commit() isn't needed after SELECT queries, only queries that modify the database. And you shouldn't call conn.close() in this function since it didn't open the connection; other functions may still need to use the connection.
def get_info(search_by=None, value=None):
valid_search_by = ['col1', 'col2', 'col3']
if search_by is None:
search_by = input("Search by: ")
if search_by not in valid_search_by:
raise ValueErr("Invalid search_by")
if value is None:
value = input("Value: ")
c.execute(f"SELECT * FROM credentials WHERE {search_by} LIKE ?", (value,))
items = c.fetchall()
for item in items:
print(f"{item[0]}", f"{item[1]}", f"{item[2]}", f"{item[3]}")
Also, there's no need to use str() in an f-string, since the formatting automatically converts the values to strings.
I am able to update the tKinter entry widgets boxes using textvariables... the issue is that it add brackets '{}' in my desired data...
def showRecord(self):
connection = sqlite3.connect("../employee.db")
connection.text_factory = sqlite3.OptimizedUnicode
cursor = connection.cursor ()
cursor.execute ( '''SELECT "Scheduled Shift" FROM employee_details WHERE Ecode = "5568328"''' )
items = cursor.fetchall ()
self.Employee1_FirstDay_ActualShift.set(items[0])
self.Employee1_SecondDay_ActualShift.set(items[1])
self.Employee1_ThirdDay_ActualShift.set(items[2])
self.Employee1_FourthDay_ActualShift.set(items[3])
self.Employee1_FifthDay_ActualShift.set(items[4])
self.Employee1_SixthDay_ActualShift.set(items[5])
self.Employee1_SeventhDay_ActualShift.set(items[6])
connection.commit ()
connection.close ()
Seeking help pls... Need to remove those brackets as shown in fig.
The reason it is doing that is because you are setting the value of a string variable to a list. Tkinter is a thin wrapper around a tcl/tk interpreter, and tcl uses curly braces to preserve the list structure when converting the list to a string when a list element has spaces or other special characters.
The solution is to make sure you pass a string to the set method. Otherewise the list will be passed to tcl/tk and it will use it's own list-to-string conversion.
In your case, since items is a list (rows) of lists (columns) and each row has a single column, you would do something like this to insert column zero of row zero into self.Employee1_FirstDay_ActualShift:
row_0 = items[0]
col_0 = row_0[0]
self.Employee1_FirstDay_ActualShift.set(col_0)
To condense that to one line, combined with all of the other rows it would look something like the following. I've added some extra whitespace to make it easier to compare each line. Also, this assumes that items has seven rows, and each row has at least one column.
self.Employee1_FirstDay_ActualShift.set( items[0][0])
self.Employee1_SecondDay_ActualShift.set( items[1][0])
self.Employee1_ThirdDay_ActualShift.set( items[2][0])
self.Employee1_FourthDay_ActualShift.set( items[3][0])
self.Employee1_FifthDay_ActualShift.set( items[4][0])
self.Employee1_SixthDay_ActualShift.set( items[5][0])
self.Employee1_SeventhDay_ActualShift.set(items[6][0])
I have the following code which creates a list box and populates it with data from a MySQL query.
self.listbox = Listbox(self)
self.data = ['All Accounts']
sql = "SELECT AccNo FROM accounts"
curs.execute(sql)
numrows = curs.fetchall()
self.data.append(numrows)
for i in self.data:
self.listbox.insert(END, i)
self.listbox.grid(row=8, column= 0, columnspan=3, rowspan=8)
The data shows up in the list box but all on one line. How can I change the code so that it populates the list box with each item in the list on a different line in the list box?
Thank you for the help in advance.
It seems like the problem is that you really only have one entry in your list, the entire contents of sql statement is assigned to "numrows". When you append numrows to your self.data list, it's doing that as one big, single entry. You're doing the equivalent of this:
self.data.append(curs.fetchall())
Which is just passing the sql return directly to your list. You'll need to parse the return info from your sql statement before adding it to the list, instead of just appending it directly to the list.