Check if entry is already done - ms-access

I am looking for a smarter way to check if a text in a record already exists.
Basically I wrote a database which stores minutes.
Since only the latest information should be stored in a textbox (there the entries are made) and "old" information goes to a history box I am looking for a way to prevent double entries in this history box.
For that reason I used the InStr Function to check if the the first 10 letters already exists in the history field it doesn't add the information. I start at position 100 since there is this header I made to differ between the entries.
Actually it works most the times but I could not figure out why it doesn't add information many times then this information is actually new so I look for a smarter way or does somebody see a mistake?
Private Sub txt_Comments_W9_LostFocus()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' History function.
' Since only the latest information should be stored at the text field the old/other information will be stored at the history box
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim temp As String
Dim newComment As String
Dim Version As String
temp = " "
newComment = " "
Version = "<b>" & "****************************************" & "Version " & Date & ": " & "****************************************" & "</b>"
newComment = Version & txt_Comments_W9.Value
If Len(Nz(txt_History_W9.Value)) = 0 Then
If Len(Nz(txt_Comments_W9.Value)) = 0 Then
Exit Sub
Else
txt_History_W9.Value = "<div>" & newComment & "<BR>"
End If
Else
temp = txt_History_W9.Value
If InStr(100, temp, Mid(txt_Comments_W9.Value, 1, 10)) = 0 Then
txt_History_W9.Value = "<div>" & temp & newComment & "<BR>"
End If
End If
End Sub
Thanks

If Len(Nz(txt_History_W9.Value)) returns 0 you will skip the check after your else. Is that on purpose?
Also, is there a reason why you are using Mid(txt_Comments_W9.Value, 1, 10) instead of Left(txt_Comments_W9.Value, 10).
And if the arguments for Instr are as follows: InStr([start,]string1,string2[,compare]), It can return:
If string1 is "" - InStr returns 0
If string1 is Null - InStr returns Null
If string2 is "" - InStr returns start
If string2 is Null - InStr returns Null
If string2 is not found - InStr returns 0
If string2 is found within string1 - InStr returns the position at which match is found
If start > Len(string1) - InStr returns 0
Make sure you know what the InStr Function returns in case of no match.

The way this table is Structured is very odd. Your table design should ideally be something like.
tbl_MinutesHistory
------------------
minID | minDate | minEntree | minNotes
--------+---------------+---------------+--------------------------------
1 | 03/04/2014 | Paul | Meeting for Boss birthday
2 | 05/05/2014 | Eugin | Meeting to elect new boss
3 | 02/06/2014 | Francis | Company shutting down meeting
Then your history box (I guess it is a Listbox) would include everything except the last date. Rowsource would be something like
SELECT minDate, minEntree, minNotes
FROM tbl_MinutesHistory
WHERE minID Not In (SELECT Max(minID) As maxOfID FROM tbl_MinutesHistory);
You are making things more complicated with code !

Related

Access 2013 - sequential numbering without autonumber

New to this site and access.
I am trying to create a database to keep track of a master log. Need help with sequential numbering. I currently have the following tables.
PO Table
POID - Autonumber(PK)
PODate - Date/Time
Supplier - String
Item Table
ItemID - Autonumber(PK)
POID - Ingeter(FK)
ItemDescription - String
Quantity - Integer
MasterLog Table
MasterLogID - Autonumber(PK)
ItemID - Integer(FK)
PieceNumber - Integer ( 1,2,3 ... etc)
MFG - String
Process - String
Length - Integer
MfgIDNum - String (ABD123XTY-1234)
I am trying to automate the data entry of the PieceNumber field. So when you enter a new PO and add items to it, once received. It will add a row to the masterlog table starting at piece number 1 through how ever many pieces we have. We number the pieces based on the items we purchased.(i.e. with Item 1 we purchased 100 pieces. So I would have Item 1 piece 1 through 100.) Then we are able to add the other data to the table. Just trying to reduce some data entry time and avoid some mistakes in the numbering of this field.
Any ideas?
Something like this would be a very simple way of doing it. You'd have to have a predefined table called Numbers with integers starting from 1 to however high a quantity you might have:
INSERT INTO MasterLog (ItemID, PieceNumber)
SELECT Item.ItemID, Numbers.Number
FROM Item, Numbers
WHERE (Item.ItemID = Forms!Items!ItemID) AND
(Numbers.Number <= Item.Quantity)
ORDER BY Numbers.Number
If you wanted to add the pieces one by one you could default the PieceNumber field on the related form. Make sure you default MasterLog.ItemID as well:
=Nz(DMax("[PieceNumber]","[MasterLog]","[ItemID] = " & Forms!Items!ItemID), 0) + 1
For a VBA solution try something like this:
Dim db As Database
Dim strSQL As String
Dim frm As Form
Dim i As Integer
Set db = CodeDb()
Set frm = Forms!Items
If frm!Quantity > 0 Then
For i = 1 To frm!Quantity
strSQL = "INSERT INTO MasterLog (ItemID, PieceNumber) " & _
"SELECT " & frm!Item & " AS ItemID, " & _
i & " AS PieceNumber"
db.Execute strSQL, dbFailOnError
Next i
End If
Set db = Nothing
All of these presume a form displaying your current item called Items.

Filtering Data from a specific column

Hello Everyone I am at a dilemma I am trying to find out a way to filter out certain data in a column field I have an idea on how to do this but I do not know the correct syntax to use. First here is the table and here is the code structure I would like to write.
for i=1 to length of column First Match
for j=1 to length of column Second Match
If ((value of the data in column First Match = 15) OR (value of the data in column FirstMatch = 1)) AND
((value of the data in column Second Match = 15) OR (value of the data in column Second Match = 1))
Then
Filter the data and append so the filtered datas are saved for both First Match and Second Match
end if
next
next
I am trying to filter out the data that is a 15 and 1 so that only data that have the values 0,2,3,4,5,6...14 will be shown for instance the information of john and steve will not be shown because both the first and second match fields have a 1 or 15 but the rest of data will be shown my form is a split form setup.
Is my method correct?
First Name Last Name First Match Second Match
James Matheson 0 2
Monroe Labonson 4 3
Barack Obama 2 5
Frederick Douglas 3 4
Steve MCGowan 1 1
John Seals 15 15
Mike Omalley 14 15
Set rs = CurrentDb.OpenRecordset("Table1")
Do While Not rs.EOF
If rs!Fields("First Match") > 1 And rs!Fields("First Match") < 15 And rs!Fields("Second Match") > 1 And rs!Fields("Second Match") < 15 Then
End If
Loop
With a better understanding (I hope) I've reproduced your data in Access and built a query that does what you seem to ask. The best way to see this is to create a new query, not add a table, and go directly to SQL view. Paste the following SQL statement (the one in quotes) in and replace matchFilter with your table name.
In your event code you can create a recordset based on the SQL:
Dim sSQL as string, rs as Recordset
sSQL = "SELECT matchFilter.[First Name], matchFilter.[Last Name], matchFilter.[First Match], matchFilter.[Second Match] " & _
"FROM matchFilter " & _
"WHERE ((([First Match]<>1 And [First Match]<>15 And [Second Match]<>1 And [Second Match]<>15)=True))"
Set rs = CurrentDB.OpenRecordset(sSQL)
' now do what you want
Wrong answer below!
Dim rs as Recordset
Set rs = CurrentDB.OpenRecordset("yourTableName")
Do While Not rs.EOF
If rs!Fields("col1") > 1 AND rs!Fields("col1") < 15 AND rs!Fields("col2") > 1 AND rs!Fields("col2") Then
'do what you have to do with filtered out records
End If
Loop
I have found the solution apparently it was just a misunderstanding because the first time I tried this code I thought it was wrong but it was because my field names did not have spaces in between the first time I wrote them.
Me.Filter = ""
Me.Filter = "[First Nam]<>'Jamie' AND [Last Nam]<>'Cartman'"
Me.FilterOn = True

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

MS ACCESS - Hierarchical tree sort

I'm struggling with a sorting problem.
I've got a table which is as follows:
aspect_id (int)
aspect_text (memo)
root_id (int) which has as a foreign key a aspect_id
I've got a non cyclic tree with the following dummy data:
aspect_id aspect_text root_id
1 root null
2 aspect1 1
3 aspect2 1
4 aspect3 2
5 aspect5 4
In the example the data is sorted correctly, in my database its not. I want to sort that it starts at the root element, then finds a child, output that child and does that recursively.
With CTE it is fairly doable. Access doesn't support this. With CTE it would be something like:
WITH aspectTree (aspect_id, root_id, Level#) AS
(
Select
aspect.aspect_id,
aspect.root_id,
0
FROM aspect
WHERE aspect.aspect_id = 44
UNION ALL
SELECT
aspect.aspect_id,
aspect.root_id,
T.Level# + 1
FROM aspect
INNER JOIN aspectTree AS T
On T.aspect_id = aspect.root_id
)
SELECT * FROM aspectTree;
If performance is not a consideration, this fairly simple solution would work:
Public Function GetLevel(ByVal lngNodeId As Long) As Long
Dim varRootId As Variant
varRootId = DLookup("root_id", "aspect", "aspect_id=" & lngNodeId)
If IsNull(varRootId) Then
GetLevel = 0
Else
GetLevel = GetLevel(varRootId) + 1
End If
End Function
You could then use that function in your ORDER BY clause:
SELECT aspect.*
FROM aspect
ORDER BY GetLevel([aspect_id]), aspect_text
I don't know if the following will work for you but here you go using Bill of Materials algorithms.
Bill Of Materials
BOM, with Joe Celko Nested Sets
Its full of test code, but i did something that works in vb code. Its really ugly and slow, but it works. Im now cleaning it up, just got it working. The solution is a recursive function. The function calls on itself if it finds that the node has childs. It seemed to overwrite the arrays, that why its an array of arrays. The code is hideous, but it works and thats all i needed. The database is and will stay small (<1000 records) so speed is not an issue. Thanks for the comments and answers, if someones knows i better solution, i would love to hear it.
Private Function Fillarray(value As Integer)
Dim done As Boolean
j = j + 1
esql = "select aspect_id from aspect where root_id = " & value
Set rec(j) = db.OpenRecordset(esql)
Dim k As Integer
k = j
Do While Not rec(k).EOF
done = True
arra(i) = rec(k).Fields(0)
Dim temp1 As String
temp1 = DLookup("[aspects]", "[aspect]", "[aspect_id] = " & rec(k).Fields(0))
db.Execute "INSERT INTO sortedaspect (aspect_id, aspect) VALUES (" & rec(k).Fields(0) & ", '" & temp1 & "')"
esql = "select aspect_id from aspect where root_id = " & rec(k).Fields(0)
Set rec(90) = db.OpenRecordset(esql)
Do While Not rec(90).EOF And done
'fix this without a loop,you only need to know if it has childs...
Fillarray (rec(k).Fields(0))
done = False
Loop
'next child
rec(k).MoveNext
'value = arra(i)
i = i + 1
'MsgBox arra(i - 1)
Loop
End Function