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
Related
I am using Access Database to get a value. I am fairly new to access as I usually use SQLServer and I am having trouble in getting what I want.
I have the following table, with column TARGET and incremental Target as the target column that I need to get:
Category|Period|Value| TARGET |
A | 4 | 1 | 1/1 =1 |
A | 3 | 3 | 1/(3*1)=0.33 | (1/value at period 3 * previous target)
A | 2 | 6 |1/(0.33*6)=0.505|
A | 1 | 9 |1/(0.505*9)=0.22|
The data is partitioned by Category and ordered in descending order by Period.
For the first row the Target should be: (1/value at current period)
For the next rows the Target should be: (1/value at current period * value of previous target)
As you can see this is somehow complex as I need to evaluate a cell value and then for the next row I need to use the value in the cell above.
Plus I need to get the incremental value for this column as well.
Any help will be very much appreciated as I am new to Access and need to get this done soon!
Here is a function placed in general module that can be called from query. Value is a reserved word so I used Data for that field name.
Option Compare Database
Option Explicit
Global dblTar As Double
Global strCat As String
____________
Function CalcTarget(strC As String, dblT As Double) As Double
If strCat <> strC Then
strCat = strC
dblTar = dblT
End If
dblTar = 1 / (dblT * dblTar)
CalcTarget = dblTar
End Function
Calling function in query:
SELECT Category, Period, Data, CalcTarget([Category],[Data]) AS Target FROM Table1;
Normally I advise not to save calculated data to table when a query can work, but if you prefer to save, then options are:
An UPDATE action: UPDATE Table1 SET Target = CalcTarget([Category],[Data]);
Or VBA:
Sub CalcTarget()
Dim rs As DAO.Recordset
Dim strCat As String
Dim dblTar As Double
Set rs = CurrentDb.OpenRecordset("SELECT * FROM table1 ORDER BY Category, Period DESC")
strCat = rs!Category
dblTar = rs!Data
Do While Not rs.EOF
If rs!Category = strCat Then
dblTar = 1 / (rs!Data * dblTar)
rs.Edit
rs!Target = dblTar
rs.Update
rs.MoveNext
Else
strCat = rs!Category
dblTar = rs!Data
End If
Loop
End Sub
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.
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 !
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...
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