Access VBA write multiple values to single text field on form - ms-access

I'm attempting to concatenate multiple values into a single text field on a form and needs help on assigning those values to the text field.
Setup: I have an access form that a user can select a drop down and choose an ID number. Selecting the ID and then clicking a button will run a query that can return one or multiple rows of results. The rows returned in the results will have duplicate data except for one field (e.g. description). I'm attempting to loop over the results and add the description to a text field on the form so that shows all the field values from each row, thus listing all the descriptions.
Example of data returned:
Columns:
ID | Issue Date | Description | CBD | ECD
Results return could be 1 or more rows: example below
17-0001 | 11/30/2017 | ABC | 12/5/2017 | 12/10/2017
17-0001 | 11/30/2017 | XYZ | 12/5/2017 | 12/10/2017
17-0001 | 11/30/2017 | LMN | 12/5/2017 | 12/10/2017
17-0001 | 11/30/2017 | QAZ | 12/5/2017 | 12/10/2017
In the text box I'm trying to add the values to I want it add the description to a single text box in order.
Text box contains:
Subject:
ID
Body Text:
ABC
XYZ
LMN
QAZ
Here is Code I have so far: It works but I just not sure how to get the description to concatenate together.
Private Sub createAnnouncement_Click()
Dim qdf As DAO.QueryDef
Dim rst As DAO.Recordset
Dim db As Database
Dim issID As String
Set db = CurrentDb
Set qdf = db.QueryDefs("nso_announce_qry")
qdf.Parameters(0) = Forms![NSO Announcements]!annID
Set rst = qdf.OpenRecordset
annSubject = rst.Fields("Issuance Title")
Do While (Not rst.EOF)
MsgBox (rst.Fields("Issuance Detail Description").Value)
rst.MoveNext
Loop
End Sub
should there be a annBody variable outside the Do while that you add in each value as it loops through?

You can "acumulate" the contents of the Description field for each record:
Dim concatenated as String
Do While (Not rst.EOF)
concatenated = concatenated + rst.Fields("Issuance Detail Description") + " "
rst.MoveNext
Loop
concatenated = Left(concatenated, Len(concatenated) - 1)

Related

Insert only enabled textboxes into MySQL in VB.Net

I am creating an inventory management system in VB.Net, where the basic function is the process incoming invoices. I would like to insert data into my remote MySQL database but only if the textbox is considered enabled. I have no issue inserting data into the database when I want it to insert all fields. But I would like to have checkboxes enable certain products and allow the employees to enter only specific items. The check boxes do enable and disable the text fields as required but when inserting data into the database it will enter null values for all product types and I don't want it doing that as it will mess up the invoicing system. Currently I tried an if then statement but the issue I ran into was that it wanted the not enabled textboxes to be defined.
Code for what I tried is:
Public Sub btnEnter_Click(sender As Object, e As EventArgs) Handles btnEnter.Click
Dim mysqlconn as new MySqlConnection ("ServerConnection")
mysqlconn.Open()
dim mysqlCmd as new MysqlCommand
mysqlcmd.Connection = MysqlConn
mysqlcmd.CommandText = "Insert into Table_Name (Column1,Column2,Column3) Values (#rec1,#Rec2,#Rec3)"
If txtTextbox1.Enabled = True then
mysqlcmd.Parameters.AddWithValue("#Rec1",Column1.text)
End If
If txtTextBox2.Enabled = True then
mysqlcmd.Parameters.AddWithValue(#Rec2,Column2.text)
End IF
IF txtTextBox3.Enabled = True then
mysqlcmd.Parameters.AddWithValue(#Rec3,Column3.text)
End If
You can't just insert a column without a row. So if you will insert one column, you must insert all columns. If you don't want to add a value, then the column could be NULL or empty string, depending on the columns in the database. Also use Using and take the database work off the UI with Async/Await
Public Async Sub btnEnter_Click(sender As Object, e As EventArgs) Handles btnEnter.Click
' if your columns take NULL to mean no value
Await AddParams(
If(txtTextbox1.Enabled, Column1.Text, Nothing),
If(txtTextbox2.Enabled, Column2.Text, Nothing),
If(txtTextbox3.Enabled, Column3.Text, Nothing))
' else, if an empty string means no value
Await AddParams(
If(txtTextbox1.Enabled, Column1.Text, ""),
If(txtTextbox2.Enabled, Column2.Text, ""),
If(txtTextbox3.Enabled, Column3.Text, ""))
End Sub
Private Function AddParams(param1 As String, param2 As String, param3 As String) As Task
Return Task.Run(
Sub()
Using mysqlconn As New MySqlConnection("ServerConnection")
mysqlconn.Open()
Using mysqlCmd As New MySqlCommand("Insert into Table_Name (Column1,Column2,Column3) Values (#rec1,#Rec2,#Rec3)", mysqlconn)
mysqlCmd.Parameters.AddWithValue("#Rec1", param1)
mysqlCmd.Parameters.AddWithValue("#Rec2", param2)
mysqlCmd.Parameters.AddWithValue("#Rec3", param3)
End Using
End Using
End Sub)
End Function
If I understand your current design,
Table_Name
ID
Column1
Column2
Column3
1
abc
def
ghi
2
jkl
mno
pqr
An incomplete invoice has empty string or NULL when one column isn't enabled
ID
Column1
Column2
Column3
1
abc
NULL
ghi
2
NULL
mno
pqr
This is what this answer does.
If your database design is flexible, perhaps a better design would be
Invoice
ID
Name
1
Invoice 1
2
Invoice 2
InvoiceRec
ID
Name
1
Column1
2
Column2
3
Column3
InvoiceItem
ID
InvoiceID
InvoiceRecID
Value
1
1
1
abc
2
1
3
ghi
3
2
2
mno
4
2
3
pqr
Now you aren't storing any null when an item is not enabled. The SQL to select would then be
SELECT
i.Name InvoiceName
, ir.Name InvoiceRecName
, ii.Value Value
FROM InvoiceItem ii
INNER JOIN Invoice i ON i.ID = ii.InvoiceID
INNER JOIN InvoiceRec ir ON i.ID = ir.InvoiceRecID
WHERE i.Name = 'Invoice 1'
InvoiceName
InvoiceRecName
Value
Invoice 1
Column1
abc
Invoice 1
Column3
ghi
This would totally invalidate the code I wrote (except keep the Async and Using) and you'd need to query multiple tables before making multiple inserts, but the design would be normalized and database storage size would be reduced.
Further, you can build your UI from the metadata tables [Invoice] and [InvoiceRec] so if wanted to add another InvoiceRec to your business, you can add in SQL, and the UI will not need to be modified.

using LINQ-to-SQL in vb.net with multiple select statement

I'm very new to vb.net and LINQ to SQL.
I have been trying the whole day to do this but it doesn't seem to work at all. all your help is highly appreciated.
I have a table named users which contains 4 columns
+---------+-----------+---------------+--------------+
| user_id | user_name | user_password | user_stopped |
+---------+-----------+---------------+--------------+
| 1 | admin | admin | false |
| 2 | user2 | 2 | false |
| 3 | user3 | 3 | true |
+---------+-----------+---------------+--------------+
I have a from with three textboxes "txtuserid" & "textusername" & "txtuserpassword" and a button name "login"
1) on the "on_click" event of the "login" button , I have this query
Dim query = From check In Me.MydatabaseDataSet.users
Where check.user_id = Me.txtuserid.Text
Select check.user_name, check.user_password, check.user_stopped
I want to do something like this:
if query.check.user_stopped= true then
msgbox("this user has no permission")
else
me.txtusername.text= query.user_name
if me.txtuserID.text= query.check.user_id and
me.txtuserpassword.text= query.check.user_password then
me.hide()
form2.show()
end if
end if
I have been trying for hours but nothing seems to work at all.
I'm using VB.net 2010 with SQL database.
All your help is highly appreciated.
In fact Linq is really simple.
Dim id as Integer
integer.TryParse(Me.txtuserid.Text, id)
Dim query = From check In Me.MydatabaseDataSet.users
Where check.user_id = id
Select check
Would simply return all users with a given Id (Me.txtuserid.Text - converted to integer, it is an integer, right?).
If you specifically want 3 columns:
Dim query = From check In Me.MydatabaseDataSet.users
Where check.user_id = id
Select New With {check.user_name, check.user_password, check.user_stopped}
But keep in mind, this version is returning anonymous type where previous one returns User type.
If you think about it, user_id is a primary key (unique). Thus you don't need to get back a "collection" as the above "query", you simply need a single User:
Dim user = Me.MydatabaseDataSet.users.SingleOrDefault(Function(check) check.user_id = id)
If that ID exists than the user has properties of that user (typed data), else NULL.
This one matches to code that you later want to execute:
if user is not nothing
msgbox("unknown user")
else
if user.user_stopped= true then
msgbox("this user has no permission")
else
me.txtusername.text= user.user_name
if me.txtuserID.text= user.user_id and
me.txtuserpassword.text= user.user_password then
me.hide()
form2.show()
end if
end if
end if
Note: I assume this is just for hobby testing purposes, in real world you would never want to store plain text passwords.

Ms Access cannot get value from record set

I'm working on an Access application (2007) in which there is an invocation of a stored procedure (SQL-Server 2012) which is supposed to return a simple result, a one column table with two records.
When executing the procedure within the Server Management Studio, it shows a result as follows:
+----------------------------------------------------------+
| One_Sticker |
+----------------------------------------------------------+
| This is the first record of the result |
| This is the second record of the result |
| This is the third and last record of the result |
+----------------------------------------------------------+
In my Access code I have (Note: I know this is to be done within a loop, but the following is for debugging purposes only):
Set RS = ADOCmd.Execute
Set blabla = RS.NextRecordset ' Get 1st record
<BP-1> Dummy_Variable = 1
Set blabla = RS.NextRecordset ' Get 2nd record
<BP-2> Dummy_Variable = 1
Set blabla = RS.NextRecordset ' Get 3rd record
<BP-3> Dummy_Variable = 1
Set blabla = RS.NextRecordset ' No more data.
<BP-4> Dummy_Variable = 1
[ means Breakpoint at this line]
I'm running this with a watch at blabla to see what is being assigned to it every step.
When looking at the watch on BPs 1, 2 and 3, blabla has a value while at BP 4 it is empty. This implies to me that the requred 3 records are indeed being returned.
The problem is the the Fields entry within blabla has nothing (and hence blabla.Fields("One_Sticker").Value is unknown).
How can i get the value of the One_Sticher field at blabla?
What am I doing wrong?
Thanks in advance for any useful suggestion.
In Access, I would normally:
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("SELECT field FROM table WHERE somecriteria ORDER BY field;")
If rs.RecordCount > 0 Then
For x = 1 to 3
blabla = rs!One_Sticker
Debug.Print blabla
rs.MoveNext
Next
End If

VB.NET -> Combobox random index

I have a question regarding comboboxes in VB.net 2010.
In my database I have 4 fields: e.g.:
idDetails | DetailsShortCode | Details_Explain | DetailsSortOrder
{autonum}1| DOA | Death on Arrival| 5
{autonum}2| NDI | No Display | 10
{autonum}3| QQA | In Research | 4
etc..
These values I pull out of the dbase (mySQL) and insert into a CheckedListBox.
I display the values as DetailsShortCode & " - " & Details_explain.
I use a [for loop] to create index numbers, because the sort order is based on the Details Sort order. Which means that VB.net gets 'fed' with the results in the following order:
idDetails | DetailsShortCode | Details_Explain | DetailsSortOrder
3 | QQA | " ... " | 4
1 | DOA | "...." | 5
2 | NDI | " ... " | 10
If i put this in the listbox, the error I shall receive is '3 is an incorrect value for 'index'"
Due to the fact that VB.net expects that the CheckedListBox (and also ComboBox) index always is in a sequential order, as in 0,1,2,3,4..etc..
The problem is the fact that orders in the database can change, items can change, and I have a field in another table containing a comma separated list of the details selected (e.g. 1;10;14;12;)
This means that 1 always must be the item with PrimaryKey 1, and that the displayed item on that index must always be the same...
so what I need, is to know how I can use the Primary Key as an Index Number, and let VB.Net not throw an error when the Index is in a random order.., or give the items a hidden value (like in HTML and PHP), in which I can just use the [for loop] indexes..
This is the code I use to insert items to the Details CheckedListBox
Function LoadComboBoxes(ByVal CB As String)
Dim SQLtext = ""
Select Case CB
Case "Details"
SQLtext = "Select " & _
"idDetails, " & _
"DetailsCode, " & _
"DetailsExplain, " & _
"DetailsSortOrder " & _
"FROM Details order by DetailsSortOrder"
Dim i = -1
Dim dr As MySqlDataReader
Dim cmd As New MySqlCommand(SQLtext, dbconn)
connect()
dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)
CLBDetails.Items.Clear()
While dr.Read
i += 1
CLBDetails.Items.Insert(i, .GetString(1) & " - " & dr.GetString(2))
End While
end select
end function
The easiest way might be to use a DataGridView which should have all the functionality of the CheckedComboBox plus the ability to keep the data intact as column data and allow you to reference the ID column as an ID Column rather than an ID aliased as an Index.
Depending on what a CheckedComboBox is (there are lots of these around) and what it inherits from, you should be able to store objects there:
Class DisplayItem
Friend ID as Long
DetailsShortCode As String
Details_Explain As String
DetailsSortOrder As String
Public Function overrides ToString As String
' depending on the CheckedComboBox add column seperators?
return DetailsShortCode & Details_Explain & DetailsSortOrder
End Function
End Class
Adding an object such as this to the control lets you retain the PK ref:
ccb.Items(N).ID
While the ToString function lets you format the output as desired. Further, you could create a List(Of DisplayItem) or BindingList(Of DisplayItem) and drive the CheckedComboBox by binding the datasource to the List. A DGV is still easier...

function to check a text field

im using access 2007 and i need a function that will check a text field and if it found a certain word it will return a certain value according to lookup table
for example i have a text field as following :
ID Text
| 1 | engineers for mechanical work
| 2 | engineers for civil work
| 3 | engineers for electrical work
and i have lookup table as following :
Checkwords showords
| mechanical | mechanical engineer
| civil | civil engineer
| chemical | chemical engineer
| electrical | electrical engineer
| maintenance | maintenance engineer
| electronics | electronics engineer
i need the function to check the text records and if it found text like "mechanical" it will show "mechanical engineer" and if it found text like "civil" it will show "civil engineer" and so on
i have about 200 words to check so i need a function that uses a lookup table with "like" parameter ... is that possible ???
OK then, a more generic version, though be warned - the more you lean on VBA rather than SQL, the slower things get with large and even not-so-large amounts of data:
(1) Add a class module, name it LookupData, and add the following fields to it:
Public Key As String
Public Value As String
(2) In a standard module, define the following function:
Function LookupShowWords(ByVal Text)
If IsNull(Text) Then
LookupShowWords = Null
Exit Function
End If
Dim Data As LookupData
Static LookupTable As VBA.Collection
If LookupTable Is Nothing Then
Set LookupTable = New VBA.Collection
Dim RS As DAO.Recordset
Set RS = CurrentDb.OpenRecordset("LookupTable", dbOpenForwardOnly)
While Not RS.EOF
Set Data = New LookupData
Data.Key = "*" + RS(0) + "*"
Data.Value = RS(1)
LookupTable.Add Data
RS.MoveNext
Wend
End If
Dim S As String
For Each Data In LookupTable
If Text Like Data.Key Then
If Len(S) = 0 Then
S = Data.Value
Else
S = S + ";" + Data.Value
End If
End If
Next
If Len(S) = 0 Then LookupShowWords = Null Else LookupShowWords = S
End Function
(3) The query to list the results can now be rewritten to look simply like this:
SELECT ID, LookupShowWords(Text) AS ShowWords FROM MainTable ORDER BY ID;
Note that the assumption in (2) is that the lookup table is essentially static, in which case its contents can be safely cached between calls.
(1) A custom VBA function to extract the key word:
Function ExtractKeyword(ByVal Text)
Text = Mid(Text, InStr(Text, " for ") + 5)
If Right(Text, 5) = " work" Then
ExtractKeyword = Left(Text, Len(Text) - 5)
Else
ExtractKeyword = Text
End If
End Function
(2) A query to use it:
SELECT MainTable.ID, LookupTable.ShowWords
FROM MainTable LEFT JOIN
LookupTable ON ExtractKeyword(MainTable.Text) = LookupTable.CheckWords
ORDER BY MainTable.ID