I am trying to read the last row with a value in the Number column and then increase it by one. For some reason the code below is reading the second row in the table not the last? Any ideas why?
Dim dvProjectName As DataView = DirectCast(AccessDataSource1.Select(DataSourceSelectArguments.Empty), DataView)
Dim strProjectName As String = DirectCast(dvProjectName.Table.Rows(0)("Number"), Integer)
Autonumber fields are handled by the MS Jet database engine directly. Attempting to change the value yourself will usually result in an error. If you want to manipulate the values yourself - change the field to a number field and use VBA code to change the number. Else, prepare to be disappointed as Jet won't let you change the numbers.
Related
I am fairly new to access and I am working on a database to manage Bills of Materials (BOMs) of several products. I would like to create a form where the user can input a list of component names to see where these components are being used.
To run a query based on one word is simple but I am struggling to extend it to more than one word.
I would like the user to input the components separated by new lines like this:
Item1
Item2
Item3
...
If I use the text field as is then the query won't find anything because it takes the text field as a whole and not line by line.
I have tried to process the text field into a ListBox because I thought that it would be handled like an array but it does not have a <value> therefore it will not return any search results.
My next try was to use a second text field where I can format the information to the format "Item1";"Item2";"Item3" so that I can use it in an in statement.
If I directly put:
in ("Item1";"Item2";"Item3")
In the query criteria then it will run as expected, however if I try to reference the HelpText (which contains: "Item1";"Item2";"Item3") like so:
In ([Forms]![Search_mult_component]![HelpText])
Then I get no results. I have also tried formatting the text to include the parenthesis like so ("Item1";"Item2";"Item3")
As I mentinoed I am just getting to know Access therefore I am not sure if this is a good practice or if I am trying to force something which can be done in a simple way with a slightly different approach.
Thank you for the support in advance!
You can't. Just like table and field names, the value string of an IN statement must be present before the query runs.
Your only option is to write the SQL string dynamically and, say, create a temporary query to which you pass the SQL.
Using a list box to represent the selection criteria is a good approach as it will allow the user to select & manipulate multiple items as distinct elements, without having to worry about delimiters and such.
However, rather than attempting to access the value of the list box, I would suggest using the list box to populate an underlying table, which you can then join to the relevant field in your query, causing the results to be automatically filtered without the need for a where clause.
I have managed to solve it after #Lee Mac provided the spark!
I created a Table TempTable to store the input values and I was able to use this table in the query later. It still took some code to get there though!
In the form I used a textbox with the multiline data as defined in the question and a button to run the Query. The steps therefore are somewhat separated between the Textbox itself and the button.
The Textbox has the following code for the AfterUpdate event:
Private Sub search_text_AfterUpdate()
Dim TempTable As DAO.Recordset
Dim i As Integer
Dim allNums() As String
' ======= Open table =======
Set TempTable = CurrentDb.OpenRecordset("SELECT * FROM [TempTable]")
' ======= Clear table =======
DoCmd.SetWarnings False 'Disable warnings. If not disabled the user will be prompted to confirm the delete
DoCmd.RunSQL "DELETE * FROM TempTable" 'SQL statement used to delete all entries from a table
DoCmd.SetWarnings True 'Enable warnings
' ======= Process multiline text =======
allNums = Split(search_text.Value, vbNewLine) 'Split the multiline text
For i = LBound(allNums) To UBound(allNums) 'process line by line
If (StrComp(Trim(allNums(i)), "", vbTextCompare) > 0) Then 'Check if current text is empty string
TempTable.AddNew 'Add new Record to table
TempTable![ToSearch] = (Trim(allNums(i))) 'Fill in the text, trim whitespaces
TempTable.Update 'Update Table. Seems to be necessary for changes to take effect
End If
Next i
' ======= Clean up and close table =======
TempTable.Close 'Close the table
Set TempTable = Nothing 'No idea why this is needed :D
' ======= Refresh table =======
'DoCmd.SelectObject acTable, "TempTable"
'DoCmd.Requery
'DoCmd.GoToRecord acDataTable, "TempTable", acLast
End Sub
This code takes care of clearing the table TempTableand filling it with the new input. TempTable has two columns ID and ToSearch where ID is the primary key for the table and ToSearch will be populated with the input from the textbox. I have seen during the testing that when the entries from the table get deleted the new items will still receive new keys when added which worries me because the keys might run out at some point. This is a problem for the future but if you have any advice on this (for example removing the key from the table or sthing) then please let me know.
The code runs after the user hits an enter on the text field but needs a Requery of the table to take effect! This is included in the Button macro:
First the table oject is selected and a Requery is run. After this I close the table and open the actual Query which also needs to be requeried to show the correct updated values.
With this solution I was able to do what I intended to do without having to delve into the depths of SQL.
As always, I appreciate your comments!
I'm new to VBA and Access, but I do have some understanding.
I can set a field easily by using
[Field1] = Now()
What I want to do is save the name of a field into a string and use that variable to reference the field. This way I can save different field names into the variable and have the code act on which field name happens to be stored.
From what I can find, the proper way to do this is in my situation is:
Private Sub ctlUpdateButton_Click()
Dim varField as String
varField = Dlookup("[Targeted Field]", "[Other Table]")
Cases.Fields(varField) = Now()
End Sub
This code breaks on the reference to Cases.Fields(varField) and reports the error as 'Run-time error '424' Object Required.
The record source for the form is a query based on the Cases table.
I'm not familiar enough with what I'm working with to know if this is a sufficient explanation.
Not sure what you're trying to do with varField = Dlookup("[Targeted Field]", "[Other Table]")
DLookup returns the value of a field in another table
Is there only one row in that table?
If so - then your code will work in theory -
If not, you;ll have to specifiy the criteria to find the correct row
The last issue is that you can't use a table name directly in code (in your case "Cases")
If you want to change the underlying record in your form, you can modify it if the field name is in your query and it hasn't been renamed.
Simply use Me(varField) = Now()
Ok, here's the deal. I have a previously existing SQL Server 2008 database linked to an Access 2002 database via linked tables/views. Up until now, the item code has been a nvarchar type.
I have a SQL query which casts the item codes as Int and an Access 2002 linked query that uses the MAX() function to give me the highest value. It is from this highest value I wish to start incrementing the item codes by 1 every time the "New" record button is selected.
Right now, when "New" is selected, the form is blank, waiting for input. What I want to do is, when "New" is selected, to have the value of the MAX() function query passed to a variable, have 1 added to it, and the resulting value placed in the "Item Code" text box.
It sounds easy enough, but for some reason I can't seem to get it to work. I know Access fairly well, but my VBA is fairly weak.
Sound like it could be done with a custom function.
Dim rs as dao.recordset
Dim db as dao.database
Dim NextInt as string
set db = currentDb
set rs = db.openrecordset(YourMaxQuery,dbOpenSnapshot,dbSeeChanges)
if rs.recordCount >0 THEN
NextInt = Cstr(rs!MaxValue + 1)
END
set rs = nothing
set db = nothing
return NextInt
Call the function in the update statement of your query and it should give you the value you're looking for.
Sorry I took so long to get back to this thread.
Ok, I ended up going with a GlobalSequence in MS SQL Server 2008. Basically just created a table with the max id value as a seed, and matched it with a column that has a bit value to prevent rollbacks and duplicate item codes should a record get deleted. After that, it was pretty easy. :)
I'm currently working with an Access(2010) Query that is taking multiple order items and GROUPING BY the order number. For example, a customer may have ordered 5 items under order number 123 but my query groups all of these individual items into one line with each item in it's own column. The objective is each individual order number is contained on one line because the query will be exported in a .csv format to 3rd party software.
Since I'm combining multiple records/items I'm running into issues when the description field is getting truncated based on 255 characters. Since working in a query I don't see the option of changing the text field to a memo field, so that won't resolve the issue and the GROUP BY clause is capping all the text fields at 255 chars anyway.
So, my question is instead of using the description fields from the current query is there a way that I can use an additional table to lookup an items description based on the part number ordered? Proposed new table would be something very simple like:
PART | DESC
123 Widget Z_Langs_AUS_INT<br>
567 Widget K_Langs_DOM_CAN<br>
890 Widget B_Langs_SM
So the ideal statement in the query would be something like IIF TABLE1.PART#ORDERED(from current query) = NEWTABLE.PART(from new table), then obtain NEWTABLE.DESC(from new table) otherwise ""
This would return the description of a specific part number if the part number fields matched otherwise leave the field blank because it likely doesn't contain a part number.
I'd appreciate any suggestions at this point. I may be going about this all wrong when trying to resolve this issue so fresh input is welcome.
Don't write that as a query. It's too complex to bother with, and is extremely simple to do with VBA and direct text access. Add a reference to the Microsoft Scripting Runtime (scrun.dll), use internal query objects for your SQL data, and use code similar to what's below.
Sub makeText()
Dim rs1 As Recordset, rs2 As Recordset
Dim oFSO As Scripting.FileSystemObject, oFile As Scripting.TextStream
Dim txtLine As String
Set oFSO = New Scripting.FileSystemObject
oFile = oFSO.CreateTextFile("FileName.csv")
Set rs1 = CurrentDb.OpenRecordset("baseQuery")
Do Until rs1.EOF
txtLine = rs1!OrderNumber.Value
Set rs2 = CurrentDb.OpenRecordset("innerQuery")
Do Until rs2.EOF
txtLine = txtLine & "," & rs2!itemDesc.Value
rs2.MoveNext
Loop
oFile.WriteLine txtLine
rs1.MoveNext
Loop
oFile.Close
End Sub
Below is a picture from an example database we used to use. It has our parts with all the info you could need, and then the part that matches up with our vendor. The query used will display each and every row where our part matches the vendor part.
You can also just put a [AskMeForMyPart] or whatever in square brackets like that to make the query pull based on that specific part.
I am using Access 2007 and writing a macro in VBA.
"Analyze" subroutine is passed a recordset rev_rec. This recordset has two fields "PeriodNo" (Integer) and "Revenue"(double).
Minrev is a variable where I have to store the minimum value of "Revenue" field. The code that I am using is below.
Public Sub Analyze(rev_rec As DAO.Recordset)
Dim Minrev As Double
rev_rec.MoveFirst
Minrev = rev_rec("Revenue")
While Not rev_rec.EOF
If rev_rec("Revenue") < Minrev Then
Minrev = rev_rec("Revenue")
End If
rev_rec.MoveNext
Wend
rev_rec.MoveFirst
.
.
.
End Sub
I tried using DMin() with recordset but am not able to find a way to do that. Is there a way to do this without using any kind of loop?
I think your best bet is to build a new recordset using a SQL statement that only retrieves one record, the one with the minimum for the desired period. Another option is, you could open this particular recordset with the Order By on the Revenue column Ascending. This way you would know that the smallest value will be in the first record.
Andy Brown's suggestion of using DMin should also work. It's actually an idea very similar to my first suggestion.
The problem is that you're passing a recordset. If you just had the table or query name (or SQL statement), you could just use DMIN. Eg:
MinRev = DMIN("Revenue","TableOrQueryNameInQuotes","")
The third argument can be used to set some criteria. For example:
MinRev = DMIN("Revenue","TableOrQueryNameInQuotes","PeriodNo > 5")
Be warned, however, that the functions starting with D (DMIN, DLOOKUP, DSUM) run very slowly, although if you've got less than about 10,000 records you won't notice this.