How to build a function to add items to different tables - variables

I currently have several functions that do the same thing. Each function add a value to a different table. I have a subject table, a format table, a studio table, a language table etc.. Each has its own function to add to it. These tables are then used to pull their values into separate dropdowns (GUI).
I would like to create a single function that insert values into each of these tables. I use lambda to pass the name of the column. With this I add an 's' to name the table (each table have the same name as the column but plural). Then I use the variable in different place in the function.
If I take the "subject" function. The database table is called "subjects," the column is called "subject" and the input box on the GUI is called "subject_add." Therefore to pull the value from the input box I use "subject_add.get()" Same for all other dropdowns but with different wording.
What I don't know is how to make the "subject_add.get()" work if I use a variable for the word "subject." I have here the function I am currently working on.
def add_to_dropdown(column):
table_name = column + "s"
element = column + "_add.get()"
if element:
conn = sqlite3.connect(conndb.data_source)
c = conn.cursor()
c.execute(f'INSERT INTO {table_name}({column}) VALUES (?)', (element,))
messagebox.showinfo("Interest", f"A new {column} has been added to the database")
conn.commit()
c.close()
conn.close()
else:
messagebox.showwarning("Warning", f"{column} field is empty!")
column_add.delete(0, tk.END)
The table_name variable looks fine. The element variable looks fine, but the "if element:" won't work, as well as the "element" in the SQL INSERT command.
Here is the button with it's lambda command that passes the word "subject" to the function.
subject_add_btn = ttk.Button(frame_add_items, text="add ", style='a.TButton', image=arrow, compound=tk.RIGHT, command=lambda: add_to_dropdown("subject"))
subject_add_btn.place(x=480, y=50, height=35, width=90)
Hopefully, this makes sense to you. It's not very easy to explain in words. It's easier to show the code.

To resolve the issue is used the eval() functions. Here are the changes I made for it to work well:
def add_to_dropdown(column):
# This function handle all dropdown
table_name = column + "s"
element = column + "_add.get()"
if eval(element):
conn = sqlite3.connect(conndb.data_source)
c = conn.cursor()
c.execute(f'INSERT INTO {table_name}({column}) VALUES (?)', (eval(element),))

Related

Passing multiple Excel cell values to SQL query WHERE clause without referencing other queries

I have an SQL view, MyView, containing the column ID of type nvarchar.
I wish to create an Excel query which:
takes the values from a column in an Excel sheet,
composes a string corresponding to a WHERE clause for the ID column,
calls the SQL query using this parameter string.
As far as I can tell, I am trying to achieve something very analogous to
Excel cell Value as SQL query where statement
My solution is working fine on my own computer. However, when I try to share my solution with a colleague who has the same reading permissions for the database, I end up with a 'query referencing another query' problem which throws a formula.firewall error, and no data is loaded.
My solution is as follows:
I have created a data connection, Parameters, from the column named ID in Excel which contains my ID values:
let
Source = Excel.CurrentWorkbook(){[Name="Parameters"]}[Content],
#"Changed type" = Table.TransformColumnTypes(Source,{{"ID", type text}})
in
#"Changed type"
Next, I create my parameter string as a new data source, fnGetParameters:
let
Source = Excel.CurrentWorkbook(){[Name="Parameters"]}[Content],
AddString = Table.AddColumn(Source, "Custom", each "ID = " & "'" & [ID] & "' OR "),
RemoveID = Table.SelectColumns(AddString,{"Custom"}),
Custom = Text.Combine(RemoveID[Custom], ""),
Parameter = Text.Start(Custom,Text.Length(Custom)-4)
in
Parameter
which creates a nice string looking like e.g. 'ID = '1' OR ID = '2' OR ID = '3'' depending on the values in the column ID in Parameters.
Finally, I try to create my query:
let
Source = Sql.Database("MyServer", "MyDatabase",[Query="
SELECT *
FROM [MyDatabase].[dbo].[MyView]
WHERE " & fnGetParameters])
in
#"Source"
Incidentally, when removing the WHERE clause from the code above, it works fine on any computer:
let
Source = Sql.Database("MyServer", "MyDatabase",[Query="
SELECT *
FROM [MyDatabase].[dbo].[MyView]"])
in
#"Source"
so it is somehow the addition of the parameter string which causes an error.

SQL Injection from a textbox

I'm new to MS Access.
So, I wrote a SQL query(query name = qryEmployeeInfo) which shows employee information. The query outputs two columns. The employee ID(header name = employee_ID) and the corresponding employee address(header name = employee_address).
My Access form has a text box(text box name = txtEmployeeID) that I want the user to be able to enter the employee_ID into and have it output the corresponding employee_address into another text box (text box name = txtEmployeeAddress). I also want the employee_address to be in the format of a string variable so I can perform other VBA checks on it later(for example - if LIKE "California" THEN...something).
I want to write what (I think) is called an injection SQL query so that I can pull the address data from the query for that specific employee_ID. I believe the format should look like this:
Dim rs As Recordset
Set rs = CurrentDb.OpenRecordset("select employee_address from qryEmployeeInfo where employee_ID = "' & txtEmployeeID & "'", dbOpenDynaset)
Do I have this written correctly?
If so, then how do I get that output into a string variable format(variable name = strEmployeeAddress)?
After I get the employee address into a string variable format I want to simply use txtEmployeeAddress.value = strEmployeeAddress to populate the employee address text box. Again, I also want the employee_address to be in the format of a string variable so I can perform other VBA checks on it later(for example - if LIKE "California" THEN...something).
Any help you could provide would be greatly appreciated.
If employee_ID is a number field, remove apostrophe delimiters.
If employee_ID is a text field, move first apostrophe so it is within quote marks.
"select employee_address from qryEmployeeInfo where employee_ID = '" & txtEmployeeID & "'"
Then txtEmployeeAddress = rs!employee_address
However, instead of opening a recordset object, could just use DLookup.
txtEmployeeAddress = DLookup("employee_address", "qryEmployeeInfo", "employee_ID =" & txtEmployeeID)
Or even better, eliminate the VBA. The DLookup() expression can be in textbox ControlSource property, just precede with = sign.
However, domain aggregate functions can perform slowly. So instead of textbox, use a combobox for selecting employee. Include employee information in combobox RowSource. Expression in textbox references column of combobox: =combobox.Column(1). Issue is combobox has limit on how many characters can be pulled into column so if field is memo (long text) type, this approach is not feasible and should use DLookup.
The address will be available in textbox for use as long as this form is open. If you want the address to be available to other procedures even after form is closed, then need to set a global or public variable. Such variable must be declared in a module header to make it available to multiple procedures. TempVars are another way to hold values for future use. I have never used them.

Sorting Data on Form in Access 2010 by VBA

I have the following setup:
Table "Mitarbeiter" (Users) with fields: "UNummer" / "Sortierung" /....
Table "Mo01" (a sheet for every month) with fields: "UNummer" / "01" / "02" / ....
The Field UNummer in Table Mo01 is a combination field that gets Mitarbeiter.UNummer and saves it as text
I call a Form "Monatsblatt" that is based on the table Mo01.
In that Form I have a Field "fldSort" that is calling "Sortierung" from table "Mitarbeiter". The Data in that field is based on "=DomWert("Sortierung";"Mitarbeiter";"UNummer = '" & [ID] & "'")"
This works and looks like this:
I am trying to sort the form by that "fldSort" in Form "Monatsblatt" by using this code:
Form_Monatsblatt.OrderBy = "fldSort"
Form_Monatsblatt.OrderByOn = True
When I start the form with that code running, Access asks for parameters:
I tried a lot of different ways of writing the code, referencing to the field in different ways. I do NOT want to base the form on anything other then the table.
Why not ask the wide world watch "Why Access asking me for Parameter"? That would have brought you to the clue I think. Debug.Print or MsgBox your .OrderBy and you see it's "fldSort", not a valid sort. Access is assuming you want to use a parameter called fldSort, but you want the string in the variable fldSort, but it's not recognized, because of the double quotes surrounding it. Everything between 2 double quotes is interpreted as a string, even it's a var name.
Delete the quotes and everything will work fine (if your sort string is sufficent)!
Form_Monatsblatt.OrderBy = fldSort
[Update]
Late, but now I see the clue. You added a calculated field to the form, but you can't sort or filter them.
Instead of appending this field to the table, create a query and add it there, then you bind the form to the query and add the field to the form. Now you can filter and sort as you like!
The query looks like this:
SELECT *,
Dlookup("Sortierung","Mitarbeiter","UNummer = '" & [ID] & "'") AS ldSort
FROM Mo01;
Or with a join:
SELECT
Mo01.*,
Mitarbeiter.Sortierung AS fldSort
FROM
Mo01
LEFT JOIN
Mitarbeiter
ON
Mo01.ID = Mitarbeiter.UNummer;
Now you can use
Form_Monatsblatt.OrderBy = "fldSort"
Form_Monatsblatt.OrderByOn = True
because you have a bound control called fldSort.
[/Update]

Use an Access Forms Unbound text box as a Field filter in a table

Access 2013 - Reference an Unbound text box on a Form
I am currently trying to use an unbound text box [Text161] on a Form name [DCM_Gap_Servers] to sort information through a table. I want the query that I created to be able to take the users input from [DCM_Gap_Servers]![Text161] as the field that is being sorted from the table names 'Server'.
This is the SQL I am using right now in the query:
SELECT * FROM Servers WHERE "Forms![DCM_Gap_Servers]![Text161]" IS NULL
** I have already Tried:
"Forms![DCM_Gap_Servers]![Text161]" ; (Forms![DCM_Gap_Servers]![Text161]); Forms.[DCM_Gap_Servers]![Text161]
This will work at any time if I replace the Text Box reference with the actual Field name I am using, but since there are hundreds of combinations of fields, I need the reference to work.
I have looked all over, and I can't seem to find the correct answer. I am willing to do it in VBA if needed, whatever it takes to get the filtering done correctly.
Thank You.
It is:
SELECT * FROM Servers WHERE Forms.[DCM_Gap_Servers].[Text161] IS NULL
but that will just select all records whenever your textbox is Null.
So it rather is:
SELECT * FROM Servers WHERE SomeField = Forms.[DCM_Gap_Servers].[Text161]
To use the form value as a field name, you must use concatenated SQL:
strSQL = "SELECT * FROM Servers WHERE " & Forms![DCM_Gap_Servers]![Text161].Value & " IS NULL"
This you might pass to the SQL property of an existing query object:
MyQueryDef.SQL = strSQL
Or:
Constant SQL As String = "SELECT * FROM Servers WHERE {0} IS NULL"
FieldName = Forms![DCM_Gap_Servers]![Text161].Value
MyQueryDef.SQL = Replace(strSQL, "{0}", FieldName)
Of course, take care the the field name isn't a zero length string.

vb.net DAL Specify columns returned

I have a Data Access Layer class that has a method (GetPeople) that will retrieve records from a SQL Server table (people). This table has more than 20 fields, including varbinary type.
Right now, SQL query is something like
SELECT * FROM people
From my BLL class, I will call DAL.GetPeople(), which will return all columns.
What would be the best way to specify which columns to return, so I could improve performance? For example, sometimes I would like to return all fields, other times, just one or two.
UPDATE
To explain it better:
In DAL I have a method GetPeople() which calls a SQL Server function GetPeople.
In BLL I have a method GetPeople() which calls DAL.GetPeople(), after doing some business logic.
In my presentation layer, I call BLL.GetPeople().
This is working, but on SQL function, I have "SELECT * FROM people". Sometimes I would like to retrieve only one column (eg. name) from table, but in this case all columns are returned, which I think is affects performance.
So, I would like to have a kind of dynamic SELECT query on this SQL Server function, whose columns returned would depend on how I call the function...
I think you are after something like this where you can pass in a comma-seperated list of column names
Private Function GenerateQuery(ByVal columnNames As String) As String
' columnNames in the following format 'column1,column2,column3'
Dim lstColumnNames As String() = Split(columnNames, ",")
Dim strSQL As New StringBuilder
strSQL.Append("SELECT ")
For intColNumber As Integer = 0 To lstColumnNames.GetUpperBound(0)
strSQL.Append("[")
strSQL.Append(lstColumnNames(intColNumber))
strSQL.Append("]")
If intColNumber < lstColumnNames.GetUpperBound(0) Then
strSQL.Append(", ")
End If
Next
strSQL.Append(" FROM People ")
Return strSQL.ToString
End Function
You can use it like this: SqlCommand.CommandText = GenerateQuery("column1,column2,column3")
The column names are wrapped in [] symbols so you don't have to worry about reserved words causing the database to error.
Change your SQL-query to something like
SELECT column1, column2, column3 FROM people;
EDIT:
What you are going to need to do is create function that will put your SQL string together for you. When i did this before, I had all of the available fields in a checked-list control, and if i wanted them pulled, I checked them. The checked items were then put through the function to assemble the string. It should be pretty simple since there are not any joins going on.