Hi Guys Its Great to be here. I am stuck with a problem in making sequenced serial with condition in MS Access. Let's say i have number of machines working for 2 shifts. Every shift i receive a report of downtime for each machine and the same machine in the same shift could have more than one problem. My goal is to count those problems and make a sequenced serial for it. For Example i made it in Excel with countifs formula and working good - see the picture. 4 Conditions (PoNumber-Shift-MachineNumber-Zdate)
I tried everything I know in Access and got stuck. I tried Count(IIf()) but did not get the desired result and the way to do it is a recordset function and I don’t have the ability to do it. Any Help Appreciated Guys.
Edit #1 : Guys i have tried the following before
SELECT TblDownTime.PONumber, TblDownTime.Zdate, TblDownTime.Shift, TblDownTime.MachineNumber AS MachineNum, Count(TblDownTime.Shift) AS CountOfShift
FROM TblDownTime
GROUP BY TblDownTime.PONumber, TblDownTime.Zdate, TblDownTime.Shift, TblDownTime.MachineNumber
HAVING (((TblDownTime.PONumber)=[Forms]![FrmDownTime]![PONum]) AND ((TblDownTime.Zdate)=[Forms]![FrmDownTime]![Zzdate]) AND ((TblDownTime.Shift)=[Forms]![FrmDownTime]![Shift]) AND ((TblDownTime.MachineNumber)=[Forms]![FrmDownTime]![MachineNumber]));
This is a query which apply my conditions and return the last serial of each downtime reason As variable (Sr) in the form. Then after update in MachineNumber field in the form Me.Serial = Sr+1. This way works fine with one by one record but when i try to paste 20 records at the time it miscalculates and giving me duplicates sometimes. So it is not the best way to go. I need a way which work fine with pasting multiple records at the time. Thanks again.
Edit #2 i use the generated serial to be formatted like this "Num"&Serial to be like Num1,Num2 to use in the following query
SELECT TblDownTime.PONumber, TblDownTime.Zdate, TblDownTime.Shift, TblDownTime.MachineNumber,
IIf([SerialFormat]="Num1" And [MachineNumber]=[MachineNumber],[ReasonCode],"") AS Code1,
IIf([SerialFormat]="Num1" And [MachineNumber]=[MachineNumber],[Reason],"") AS Reason1,
IIf([SerialFormat]="Num1" And [MachineNumber]=[MachineNumber],[DepartmentResponsible],"") AS Dept1,
IIf([SerialFormat]="Num1" And [MachineNumber]=[MachineNumber],[StoppedFrom],"") AS From1,
IIf([SerialFormat]="Num1" And [MachineNumber]=[MachineNumber],[StoppedTo],"") AS To1,
IIf([SerialFormat]="Num1" And [MachineNumber]=[MachineNumber],[TotalDownTime/Min],"") AS TotalDownTime1
FROM TblDownTime
WHERE (((IIf([SerialFormat]="Num1" And [MachineNumber]=[MachineNumber],[ReasonCode],""))<>""));
i will try the other way in comments tomorrow, And i will be grateful if someone helps me with a recordset function that operates directly on the table and i will but it on OnClose Event in my form .. thanks a lot
Here is a procedure to consider. Call from whatever event best meets your needs.
Sub MakeNum()
Dim rs As DAO.Recordset, intS As Integer, strG As String
Set rs = CurrentDb.OpenRecordset("SELECT PONumber & MachineNumber & ZDate & Shift AS Grp, ReasonSerial " & _
"FROM tblDowntime WHERE ReasonSerial Is Null ORDER BY PONumber, MachineNumber, ZDate, Shift, ID")
strG = rs!grp
While Not rs.EOF
If strG = rs!grp Then
intS = intS + 1
rs.Edit
rs!ReasonSerial = intS
rs.Update
rs.MoveNext
Else
intS = 0
strG = rs!grp
End If
Wend
End Sub
It only edits new records where ReasonSerial is Null. If you need to recalculate sequence for all records then include an UPDATE at beginning of procedure:
CurrentDb.Execute "UPDATE tblDowntime SET ReasonSerial=Null"
Related
I performed some research how do I need to set up my DB but I need your advice how to.
I have few tables in my db ( db is for incoming material ) in this db are below tables:
Material table
incoming delivery
measurements
supplier
time measurement
Let me explain logic of this db.
When delivery come user will input some data in form (creation of incoming list) where he will basically enter all data necessary to start process of receiving. So once he hit button save record he will create record in tables incoming delivery and time measure.
Until this point everything works perfectly. When next user received this incoming list he got some data where was one hyperlink to file where they put it measurements.
And here come my problem.
I want data to be input in Access rather than to excel (form input looks much more better [yes this is most important reason :) ] ).
So for that I created table called measurements, where I plan input [incoming delivery ID], [material id], [primal key] , and that 41 another columns for measurement(this columns need to be separated cause we have many parts and each got different No. of measurement and user will get information via user form ( opening different form based on material id [this works]).
So after describing its logic I am requesting you people how do i create with 1 record to measurement table each time different numbers of measurements in measurements table for it.
put it even more simple just for case. When user hit button to save the record which creates record in delivery list will also create for example additional 5 records (this number will be based on cell value) in measurement table linked with incoming delivery. (relation is of course set up to one-many)
so in the end when i will create somehow continuous table for data input. User will see form where he got incoming delivery No. some information from other tables and as mentioned 41 items to measure 5 times ( 41 columns and 5 rows )
Hope that my explanation is clear and rly need your help i am screwed :D
Hints:
Use VBA to automate the creation of records. Look for information about DAO and/or ADO and how to use them to insert records (I personally use DAO when I work with Access, it works but it's old).
Do your homework. Before asking a question, it is important that you do your research and that you try to solve the problems by yourself. Try to help yourself before asking others. Please read this article.
Maybe this snippet of code can help you. You'll need to call this method from an event (button_clic or something in your form):
public sub addRecords(id as integer)
dim db as dao.database, rsIn as dao.recordset, rsOut as dao.recordset
dim strSQL as String
dim someValue as integer, i as integer ' Test values
' "Connect" to your current database
set db = currentdb
' Create a recordset with the input data you need (read only)
strSQL = "select * from tbl_inputTable where id=" & id
set rsIn = db.openrecordset(strSQL, dbOpenDynaset, dbReadOnly)
' Create a recordset to your output table
set rsOut = db.openRecorset("tbl_outputTable", dbOpenDynaset, dbAppendOnly)
' Read the data from the input table
with rsIn
.moveFirst
someValue = rsIn![aField]
end with
' Write some test data to your output table
with rsOut
for i = 1 to someValue
.addNew
rsOut![fk_id] = id
rsOut![theValue] = i
.update
next i
end with
' Close every recordset and databases (this does not close your application)
rsIn.close
rsOut.close
db.close
end sub
In your input form, write this in the "On Click" event:
sub button1_click()
call addRecords(txtId.value) ' I am assuming that there's a text box called "txtId"
end sub
This is just a sample of what you can do with DAO. I won't (and maybe nobody else would) write the full code for you: You'll need to fit this to your particular problem.
here is the situ ation I have many sheets all displaying the same columns in the same order and they have different data in them, Im trying to write a Macro to insert a column next to the cost one and to create a runing summ or incremental sum, this column will then be copied to a new sheet later on. After a tries I have managed to get close to my goal, the problem is that my macro does the same calculation over and over again, without summing the cost column. it gets clearer if you look at the code I'm posting below. all help to solve the problem would be appreciated.
Sub IncCost()
Dim r As Range
Set r = ActiveSheet.Range("A1").CurrentRegion
Columns("H:H").Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Range("H1").FormulaR1C1 = "Incremental cost"
Range("H2").FormulaR1C1 = Cells(2, 7)
Range("H3").FormulaR1C1 = "=" & Cells(3, 7) & "+" & Cells(2, 8)
Range("H3").AutoFill Destination:=Range("H3:H" & r.Rows.Count)
End Sub
Perhaps:
Range("h3:h" & r.rows.count).formular1c1 = "=RC[-1]+R[-1]C"
I have a number of buttons on a form which provide additional information to the user, each using DCount to see if there is any information to display and if so, opening a popup form to display it. All had been working well but now for one particular button, it is taking anything between 30 seconds and a minute to open the popup form, which is obviously unacceptable. Can't understand why it worked fine originally but has now gone so slow. All the other buttons still open their form in under a second. VBA is:
Private Sub btnNotes_Click()
'open the popup notes for the current record, if there are associated records
If DCount("ID","qlkpIDForNotes") = 0 Then
MsgBox "There are no notes for this patient", vbOKOnly, "No information"
Else
DoCmd.OpenForm "fsubNotes",,,"ID = " & Me.displayID
End If
End Sub
The table being queried has approx 40,000 rows, where the largest table checked for the other buttons has about 12,000. Have tried doing the DCount directly on the table rather than through a query, but doesn't make any difference. Also tried taking out a section of the data from the original table, copying about 1100 rows into a new table and testing on that. It still took 12 seconds to open.
Any ideas, anyone?
Using DCount() just to find out if there are any row in the table or query can be rather inefficient since DCount() will have to run the whole query and go through all records to return the total count just so you can compare that to 0.
Depending on the complexity of that query, and the joins in it, and whether the joins use fields that have indexes or not, the cost of having to run that query can be exponentially proportional to the number of records in the underlying tables.
To solve your issue try this:
make sure there is an index on the underlying table's ID field in the qlkpIDForNotes query, and that all fields used in the JOIN or WHERE clauses also have indexes.
check if you can use the main underlying table or use a simplified query just to test if there are records that may be returned by qlkpIDForNotes, in short, you may not need to run that query in full just to find out if it would have some records.
use a separate function such as HasAny() below instead of DCount() when you only need to find out if a query returns any results:
'-------------------------------------------------------------------------'
' Returns whether the given query returned any result at all. '
' Returns true if at least one record was returned. '
' To call: '
' InUse = HasAny("SELECT TOP 1 ID FROM Product WHERE PartID=" & partID) '
'-------------------------------------------------------------------------'
Public Function HasAny(ByVal selectquery As String) As Boolean
Dim db As DAO.database
Dim rs As DAO.RecordSet
Set db = CurrentDb
Set rs = db.OpenRecordset(selectquery, dbOpenForwardOnly)
HasAny = (rs.RecordCount > 0)
rs.Close
Set rs = Nothing
Set db = Nothing
End Function
With this, you can simply rewrite your code as :
Private Sub btnNotes_Click()
'open the popup notes for the current record, if there are associated records '
If Not HasAny("qlkpIDForNotes") Then
MsgBox "There are no notes for this patient", vbOKOnly, "No information"
Else
DoCmd.OpenForm "fsubNotes",,,"ID = " & Me.displayID
End If
End Sub
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.
I have a job-tracking system, and there is a query that returns results of all jobs that are overdue.
I have a form that displays each of these jobs one-by-one, and has two buttons (Job has been completed, and Job not completed). Not completed simply shows the next record.
I cannot find a way to get access to the current record to update it's contents if the "Has been Completed" button is pressed, the closest I can get is the long number which represents the records position in the form.
The VBA to get the index of the record in the form is as follows.
Sub Jobcompleted(frm As Form)
Dim curr_rec_num As Long
curr_rec_num = frm.CurrentRecord
End Sub
This is my first shot at VBA, and after an hour of searching I cannot find anything to solve my problem.
Am I going about this the entirely wrong way? Working in Microsoft Access 2007
Further Info All tables are normalized
Vehicle Table: Contains vehicle_id(pk), as well as rego and model etc
Job Table: Contains job_id(pk), vehicle_id(fk) and other info about what needs to happen, as well as the next occurance date, days between each occurance of the job (all jobs repeat) and other info
Job History Table: Contains job_history_id(pk), job_id(fk), date completed and comments
When the job completed button is pressed, it should create a new entry in the job history table with the current date, any comments and the job id
This is the script I am trying to get working
Private Sub Command29_Click()
Dim strSQL1 As String
Dim strSQL2 As String
Set Rs = CurrentRs
Set db = CurrentDb
strSQL1 = "INSERT INTO completed_jobs(JOB_ID, DATE_COMPLETED, COMMENTS) VALUES " & Rs!job.ID & ", " & Date
db.Execute strSQL1, dbFailOnError
strSQL2 = "UPDATE job SET JOB_NEXT_OCCURANCE = JOB_NEXT_OCCURANCE+JOB_RECURRANCE_RATE WHERE job.ID = Rs!job.ID"
db.Execute strSQL2, dbFailOnError
End Sub
Note: Line Set Rs = CurrentRs is completely incorrect, I believe this is what I need to figure out? This is called on button-press
I am posting an image which shows the form (non-continuous).
#HansUp, I get what you are saying, but I dont quite think it's applicable (I did not provide enough information first time around for you to understand I think)
#sarh I believe this Recordset that you are talking about is what I need, however I cannot figure out how to use it, any hints?
#Matt I am 90% sure I am using a bound form (Like I said, new to Access, been looking at everything people have suggested and learning as I go). There is of course an ID for the job (Just not shown, no need to be visible), but how would I access this to perform an operation on it? SQL I can do, integrating with Access/VBA I am new at
As I understand your situation, your form is data-bound bound (you can get record index), so - your form already located on this record. If you need to update some field of underlying dataset, you can write something like
Me!SomeField = ...
DoCmd.RunCommand acCmdSaveRecord
If your form has control bound to "SomeField", then the form will be updated automatically.
If this will not help, you can look to a couple of another directions:
1) Update records using SQL code. For example, you have ID of record that should be updated in the form data set, so you can write something like:
Call CurrentDB.Execute( _
"UPDATE SomeTable SET SomeField = SomeValue WHERE SomeTableID = " & Me!SomeTableID, dbSeeChanges)
2) You can look at the Bookmark property - both Recordset and Form has this property, it describes the record position. So you can write something like this (not the best example, but can help you to get an idea):
Dim Rs as Recordset
Set Rs = Me.RecordsetClone 'make a reference copy of the form recordset
Rs.Bookmark = Me.Bookmark 'locate this recordset to the form current record
Consider a simpler approach. I doubt you need to be concerned with the form's CurrentRecord property. And I don't see why you should need a command button for "Has been Completed" and another for "Has not been Completed".
Add a "Yes/No" data type field to the table which is used by your form's record source. Set it's default value property to 0, which represents False or No. Call it "completion_status". Create a new form using that record source. Then your form can have a check box control for completion_status.
Newly added records will have False/No as completion_status --- the check box will appear unchecked. The completion_status for other records in the forms can be toggled between Yes (checked) and No (unchecked) using the check box control.