Thanks very much for your responses. Comments in-line below. I wrote a lot
of stuff, but I really have only one question (unless somebody feels
inclined to make suggestions). I have marked the question with a line of
asterisks. The database is fairly difficult to describe, but seems to be
working as intended, except that I have the question. Also, I have left out
a few details that do not seem important in this context.
Jeff Boyce said:
Please see comments in-line below...
No "layout" description of tblParts?
If you mean how it fits into the structure, it goes like this:
A ProcessPlan is a predetermined set of operations for processing a part or
a category of partsthat is developed by Engineering and approved by the
customer; a recipe, if you will. The cookbook is written before the meal
preparation begins.
A Process Plan has a unique identifying number such as 06-01. This is
stored in tblPlan. Since the numbering system could conceivably change, a
separate autonumber field is the PK. Autonumber is the PK for all tables.
All FK fields are therefore Long Integer.
A Process Plan consists of Operations such as Grind, Blast, etc. There is a
finite list of operations used for all Process Plans. These Operations are
stored in tblOp.
A Process Plan may be for one part, or for several parts that are very
similar. The Part Numbers are customer designations. They are stored in
tblPart.
A Process Plan consists of many operations, and each operation may be part
of many Process Plans (many-to-many). The junction table tjctPlanOp
resolves this relationship.
A Process Plan may be for many parts, and a part may be processed according
to several different ProcessPlans (many-to-many). The junction table
tjctPlanPart resolves this relationship.
tblProcessPlan
PlanID (PK)
PlanNumber (our designation)
tblOp
OpID (PK)
OpDescr (Grind, Blast, etc.)
tjctPlanOp
PlanOpID (PK)
PlanID_PlanOp (FK to tblProcessPlan)
OpID_PlanOp (FK to tblOp)
tblPart
PartID (PK)
PartNumber (customer designation)
PartDescription
tjctPlanPart
PlanPartID (PK)
PlanID_PlanPart (FK to tblProcessPlan)
PartID_PlanPart (FK to tblPart)
This information is entered as a data entry chore before any work is done.
There is a form (frmProcessPlan) based on tblProcessPlan, with subforms
based on tjctPlanOp (fsubPlanOp) and tjctPlanPart (fsubPlanPart).
fsubPlanOp has a combo box bound to PlanID_PlanOp (the FK field in
tjctPlanOp). The row source for the combo box is tblOp. In similar manner,
fsubPlanPart has a combo box bound to PlanID_PlanPart (the FK field in
tjctPlanPart). The row source for the combo box is tblPart. The user
enters the Plan identifying number in the main form, selects operations to
populate the fsubPlanOp record source (tjctPlanOp), and selects parts to
populate the fsubPlanPart record source (tjctPlanPart).
This results in a ProcessPlan with a list of associated Operations, and a
list of Parts that may be processed according to the ProcessPlan. This
information sits in the database until needed.
From what I found below, the "Process Plans" are actually stored in
tjctPlanOp, right? Isn't that the table that associates a given plan with
the operations that plan includes?
I hope I have succeeded in explaining above that the ProcessPlan is stored
in its own table, but contains very few details. I will just mention that
there are some description fields and such that do not enter into the
discussion, so I have left them out of the description. tjctPlanOp stores a
list of Operations that are associated with a particular ProcessPlan.
Is this the same as a Process Plan? Is this the set of related records in
tjctPlanOp?
No. A job is a specific order sent in by a customer to process a single
part number according to a specified ProcessPlan. Back to the earlier
analogy, the ProcessPlans are recipes that are written down, and are stored
until needed. In a restaurant the waiter takes the Order (one item per
customer in this strange restaurant, but they can order any quantity of that
one item), then brings it into the kitchen where it is processed according
to the recipe specified on the Order. The recipe consists of one item from
the menu (the PartNumber), which is processed through several operations
(Chop, Fry, etc.) according to the recipe (ProcessPlan).
The recipe is the ProcessPlan. The menu is the list of Parts. The Order is
a menu item (Part) that is processed according to a recipe (ProcessPlan).
An Order is a Job. Jobs are stored in tblJob.
tblJob
JobID (PK)
PartID_Job (FK to tblPart)
PlanID_Job (FK to tblProcessPlan)
JobDate
JobNumber (from our in-house numbering system)
Quantity (number of parts being processed)
Completed (Y/N)
A form (frmJob) bound to tblJob is used for entering this information. The
Receiving department will enter the JobNumber and the Quantity of parts
being processed. They will select the ProcessPlan specified by the
customer, and will be presented with a filtered list of Parts that may be
processed according to the specified ProcessPlan. They will select one
part. Selection is done by way of combo boxes. These selections will be
bound to the two FK fields in tblJob.
Let's say the job is for 100 parts (that is, 100 separate instances of a
single part number). If the job is processed without a hitch there is no
more data entry except to mark the job as complete. However, if it is
discovered at, say, the Blast operation that the previous Grind operation is
incomplete for 10 out of 100 parts, the parts are sent back to the Grind
operator for rework, and the quanity sent back is recorded. One more table
comes into play to record this information. Each Job may contain several
Operations (from the ProcessPlan that is associated with the job) needing
rework, and each Operation (Grind, for instance) may be associated with any
number of different Jobs, so there is a junction table (tjctRework) between
tblJob and tblOp. I'm not sure this relationship is necessary or helpful,
but I think it is since the aim is to select an Operation and generate a
report on how often it needs rework. The idea is that an operation needing
frequent rework may need to be redesigned. This database's purpose is to
identify such things.
tjctRework
ReworkID (PK)
JobID_Rework (FK to tblJob)
OpID_Rework (FK to tblOp)
QuantityReworked
Here is the part where the operator enters this information. The operator
on the shop floor will select the JobNumber (which is on the paper Order he
has in hand), and will be presented with a form bound to tblJob. He will
see only the necessary information: JobNumber, PlanNumber, PartNumber and
Quantity are probably enough. Therre will also be a listing of the
Operations associated with the Process Plan. The following SQL (copied from
the previous posting) can be used to populate an unbound list box:
SELECT tjctPlanOp.PlanOpID, tblOp.OpDescr,
tjctPlanOp.PlanID_PlanOp,
tjctPlanOp.OpID_PlanOp, tblJob.JobNum, tblJob.JobID
FROM tblOp
INNER JOIN (tblJob RIGHT JOIN tjctPlanOp
ON tblJob.PlanID_Job = tjctPlanOp.PlanID_PlanOp)
ON tblOp.OpID = tjctPlanOp.OpID_PlanOp
WHERE (((tblJob.JobID)=[txtJobID]))
ORDER BY tjctPlanOp.PlanOpID;
I don't know if it is the most efficient SQL, but it produces a listing of
Operations in the order they are performed for the particular ProcessPlan.
I will mention that for now the autonumber PK in tjctPlanOp determines the
order in which the operations are listed, but I will change that to an
incrementing number (using DMax and adding 1 for each new record).
During the ProcessPlan data entry chore described above, the user enters
something like:
ProcessPlan: 06-01
Parts:
123456
654321
Operations:
Grind
Blast
Weld
Grind
Burnish
At Receiving they assign a JobNumber, enter the number of parts, select a
ProcessPlan (06-01, for instance), and select one of the parts that may be
processed according to that ProcessPlan (123456, for instance).
The Operators on the floor see something like:
JobID: 00022 (PK is 999 - not seen by users)
ProcessPlan: 06-01 (key field is 02 - not seen by users))
Part Number: 123456
Quantity: 100
Operations:
Grind (01)
Blast (02)
Weld (03)
Grind (04)
Blast (05)
Burnish (06)
The numbers in parentheses for the Operations represent the PK from
tblPlanOp. The operators do not see them. The Operations are listed in the
list box. The point here is that each of the listed Operations is
associated with a ProcessPlan and a Job.
Let's say that at the second Blast operation it is discovered that more
Grinding is needed on 10 of the parts. They will select the JobNumber from
among open jobs, and will see the above (minus the stuff in parentheses). I
would like them to click on the second Grind operation (the one with the
number 04, but all they need to see is that it is the one after the Weld
operation). This will open a pop-up form in which they will enter the
number of parts reworked. The record thus entered needs to be associated
with the Job, the ProcessPlan being used for the Job, and the particular
Operation (04 in this case). There may be a Comments field, and maybe one
or two other items, which is why I am not inclined to use an Input box,
which I do not believe will work well for entering data into multiple fields
(but maybe I'm wrong).
It sounds like the "job" is the "processing" of a number of duplicate
parts (i.e., same part number).
Exactly.
"many-to-many" to what?
I hope I have explained this adequately above.
Do you need a ReworkDate field in here too?
Probably not. The job has a start and end date (I didn't mention the end
date).
If you want to report on rework associated with a particular operation
across all jobs, why are you recording the JobID in the Rework junction
table?
We may need to go back to a particular job and view its history.
"the second Grind operation" implies that there is some sequencing. I
don't recall seeing anything in your tjctPlanOp table that holds
sequencing info...
As I mentioned, I intend to use a number incremented with code, so that the
first Operation entered for a ProcessPlan has a lower number than the next
Operation entered.
I have decided that a list box may be the best way to display the
operations. (The other option, I suppose, is a subform, using SQL
somewhat similar to the following, except that the Link Parent and Link
Child properties simplify the code; that is, the WHERE is not needed).
The list box is unbound. This is its Row Source SQL:
SELECT tjctPlanOp.PlanOpID, tblOp.OpDescr, tjctPlanOp.PlanID_PlanOp,
tjctPlanOp.OpID_PlanOp, tblJob.JobNum, tblJob.JobID
FROM tblOp
INNER JOIN (tblJob RIGHT JOIN tjctPlanOp ON tblJob.PlanID_Job =
tjctPlanOp.PlanID_PlanOp)
ON tblOp.OpID = tjctPlanOp.OpID_PlanOp
WHERE (((tblJob.JobID)=[txtJobID]))
ORDER BY tjctPlanOp.PlanOpID;
Its effect is to display a list of the operations associated with the
Process Plan that is being used for the job. Each row includes the name
(and PK) of the operation, the ID number associated with the ProcessPlan,
and the ID number associated with the process. In short, each row is
uniquely identified as being associated with a particular ProcessPlan and
a particular job.
If the PKs and IDs are being displayed too, this is probably more info
than the floor folks need to see.
Agreed. I don't intend them to see any of the key fields.
I can imagine a procedure, code behind a double-click event in the
listbox, that gathers the OpID (?and PlanID?), pops up an InputBox to
gather the Rework Quantity from the user, then writes the record.
Without having all the data you have, and spending time experimenting with
different approaches, I'm not sure that I could advise on a "best" way
(not that I'm volunteering!<g>)
***********************
My *only* question at this point has to do with entering the rework
information. A rework record needs to be associated with a Job, a Part
(which is included with the Job record), a ProcessPlan (also included in the
Job record), the specific Operation from the ProcessPlan (04 in the example
above), and the generic name of the Operation (such as Grind, which the
database identifies by its PK in tblOp). This information is contained
either in the list box or in the Job record.
It would be literally possible to display all of the key fields, and have
the operator copy them to the Rework record. However, the only reasonable
way to do this is to have the key fields automatically included in the
Rework record.
No need for OpenArgs. Take a look at InputBox.
Discussed briefly above. Will it work for multiple fields? I need the
database to be as flexible as is possible, in case features need to be added
later.