Recursion - Bill of Materials

Recursion - Bill of Materials

Post by Al Solte » Sat, 14 Jun 1997 04:00:00



I have been blessed with the "opportunity" to design and develop an
indented bill of materials for our company, to replace the flat file
Vax/Cobol structures we have at present.  Most of the initial analysis
is complete, and I have been experimenting with a few data models and
algorithms.

Recursion is the tool of choice for traversing this structure, and
Paradox is not handling it very well.  5.0 under Win95 was not even
worth talking about. 7.0 would have been alright if I didn't need to do
anything more than count the iterations.

When all I did was increment a counter I achieved 9300 recursive calls
before I overflowed the stack.  As soon as I tried to open a tcursor, it
dropped to 130, and ended with the "Some Internal Limit" error.  This
was not affected by adjustments to the filehandles or config.sys.  I may
be able to get away with not opening the tcursor in the method, I didn't
like that anyway, but every variable I declared, every assignment I
made, rapidly reduced the number of times I could call the routine.  If
I had put any real code in it I would never be able to use it.

I had thought that nesting in Paradox was close enough to unlimited to
not need consideration, and I have always considered recursion a form of
nesting. Perhaps I'm wrong.

Does anyone have any ideas on how to deal with this problem?  Writing
the routines in Delphi has been considered, but none of us are up to
speed with that yet (too much else to do).  And for that matter, we
don't know if that would work either.

Al Solter
Primex Technologies
Red Lion, PA

 
 
 

Recursion - Bill of Materials

Post by Jochen Doerman » Sun, 15 Jun 1997 04:00:00



        [snip]

> Recursion is the tool of choice for traversing this structure, and
> Paradox is not handling it very well.  
        [snip]

> Al Solter
> Primex Technologies
> Red Lion, PA

Please supply some more information about the data model and the
relevant linking fields.  Are you trying to recursively traverse a
single table that contains both parant & child records?  Are you
starting at the root and attempting to find all the leaves or at a leaf
and attempting to find the root?

-- Jochen

---

When replying directly to my emial address, remove the leading x.  The x
was added to prevent automated address retrieval and the resulting
spam.  Sorry about the inconvenience.

 
 
 

Recursion - Bill of Materials

Post by Al Solte » Sun, 15 Jun 1997 04:00:00


Quote:> Please supply some more information about the data model and the
> relevant linking fields.  Are you trying to recursively traverse a
> single table that contains both parant & child records?  Are you
> starting at the root and attempting to find all the leaves or at a leaf
> and attempting to find the root?

Actually, my data model, and even my structure is not what is in
question at this point. It has come down to, why, as soon as I start to
add code to a recursive algorithm, especially if I want to open a
tcursor, does the available iterations drop down to an unusable level?

Example:

method Again(Level smallint)
   Level = Level + 1
   Message(Level)
   if Level < 10000 then
      Again(Level)
   endif
endMethod

method run(var eventInfo Event)
   Again(0)
endMethod

Using 7.0, Win95, the above iterates 9300 times before overflowing the
stack. (It was 193 times with 5.0) If I declare a tcursor, the number
drops to 5600, add 3 number variable declarations and I'm down to 4400,
and I still haven't done anything.  In the real code I will be operating
on at least 2 tcursors, possibly using arrays, setting ranges, scanning,
making assignments, etc.  I've actually tried building some of the real
code, and the overflow point had already dropped to 29 iterations.

Our manufacturing structure requires tracking labor costs, s*rates,
etc at every stage of the production process. There can be over a
hundred processes to a finished product, each linked to the previous
process and to the materials entered in at that process, This is
basically a child table which references the parts included in its
assembly, including other children listed in the same table,
approximately thus:

| Part* | PartLevel* | DetailPart* | DtlLevel* | Type | Qty |
  C          1           B            2         S      1
  C          1           X                      R      3
  C          1           y                      R      1
  B          2           B            1         S      1
  B          2           Z                      R      1
  B          1           W                      R      3
  B          1           A            2         S      1
  A          2           A            1         S      1
  A          1           V                      R      10

This reads as follows:  "S"ubPart A-1 is made from 10 of the "R"aw
Material V, Then we do something to A-1 to make it into A-2 (machine it,
for instance).  We now Make B-1 from the A-2 and 3 of W. We then add Z
to B1 (and maybe machine this, or paint it, etc) to make it into B-2.
We then add X and Y to B-2 to make C-1, which we then sell.

This is a bit simplified, but it is accurate.  I need to be able to
traverse this structure efficiently, passing the dtlPart to the
recursive method so it will be treated as the "Part" within it.  I need
to be able to do this from any point to any point, and to be able to
rollup total quantities and costs for each end product.

Since this is a pretty standard, if basic, MRP type structure, there has
to be someone out there who has tried something like this with Paradox
before.  (An SQL server is not an option, YET, and with Paradox as the
front end, it may not help anyway.)

I appreciate any input.

Al Solter
Primex Technologies
Red Lion, PA

 
 
 

Recursion - Bill of Materials

Post by Jochen Doerman » Mon, 16 Jun 1997 04:00:00



> > Please supply some more information about the data model and the
> > relevant linking fields.  Are you trying to recursively traverse a
> > single table that contains both parant & child records?  Are you
> > starting at the root and attempting to find all the leaves or at a leaf
> > and attempting to find the root?

> Actually, my data model, and even my structure is not what is in
> question at this point. It has come down to, why, as soon as I start to
> add code to a recursive algorithm, especially if I want to open a
> tcursor, does the available iterations drop down to an unusable level?

> Example:

> method Again(Level smallint)
>    Level = Level + 1
>    Message(Level)
>    if Level < 10000 then
>       Again(Level)
>    endif
> endMethod

> method run(var eventInfo Event)
>    Again(0)
> endMethod

> Using 7.0, Win95, the above iterates 9300 times before overflowing the
> stack. (It was 193 times with 5.0) If I declare a tcursor, the number
> drops to 5600, add 3 number variable declarations and I'm down to 4400,
> and I still haven't done anything.  In the real code I will be operating
> on at least 2 tcursors, possibly using arrays, setting ranges, scanning,
> making assignments, etc.  I've actually tried building some of the real
> code, and the overflow point had already dropped to 29 iterations.

> Our manufacturing structure requires tracking labor costs, s*rates,
> etc at every stage of the production process. There can be over a
> hundred processes to a finished product, each linked to the previous
> process and to the materials entered in at that process, This is
> basically a child table which references the parts included in its
> assembly, including other children listed in the same table,
> approximately thus:

> | Part* | PartLevel* | DetailPart* | DtlLevel* | Type | Qty |
>   C          1           B            2         S      1
>   C          1           X                      R      3
>   C          1           y                      R      1
>   B          2           B            1         S      1
>   B          2           Z                      R      1
>   B          1           W                      R      3
>   B          1           A            2         S      1
>   A          2           A            1         S      1
>   A          1           V                      R      10

> This reads as follows:  "S"ubPart A-1 is made from 10 of the "R"aw
> Material V, Then we do something to A-1 to make it into A-2 (machine it,
> for instance).  We now Make B-1 from the A-2 and 3 of W. We then add Z
> to B1 (and maybe machine this, or paint it, etc) to make it into B-2.
> We then add X and Y to B-2 to make C-1, which we then sell.

> This is a bit simplified, but it is accurate.  I need to be able to
> traverse this structure efficiently, passing the dtlPart to the
> recursive method so it will be treated as the "Part" within it.  I need
> to be able to do this from any point to any point, and to be able to
> rollup total quantities and costs for each end product.

> Since this is a pretty standard, if basic, MRP type structure, there has
> to be someone out there who has tried something like this with Paradox
> before.  (An SQL server is not an option, YET, and with Paradox as the
> front end, it may not help anyway.)

> I appreciate any input.

> Al Solter
> Primex Technologies
> Red Lion, PA

I was sondering about the datamodel because it can very much effect how
you are doing things.  Paradox evidently has some limitation.  Whether
that's related to how it handles recurssion or how it handles memory
management, or whatever it is, it's a limitation er have to live with.
So how do we live with it?

I think what you've got to try to do is remove as much of the code and
as many of the variables from the recursive routine as possible, and
move it to another procedure/method invoked from the recursive routine.

Every recursive call must save the entire state of things currently
going on.  If you have 2 or 3 tCursors opened, they must all be save in
some way and then opened again in the next iteration.  I'm not sure, but
I can imagine that a tCursor takes up a bit of memory when it's opened.
If at all possible, don't open any tCursors in the recursive routine.
Open it before you call the recursive routine and pass the tCursor as a
parameter or define the tCursor variable at a level that's accessable to
the recurssive routine.

 If all the work can done in another procedure/method to which you pass
a few parameters and which passes something back, it will release all
the memory when it returns to the recursive routine, thus saving
additional additional memory.  If you open any tCursors in routines
called from the recursive routine, explicitly close them before
returning.  (I'm not sure if this saves memory.  You might want to
experiment with this.)

Hope this helps.  Good Luck.

-- Jochen

---
Remove leading _x_ from e-mail address if responding directly.

 
 
 

Recursion - Bill of Materials

Post by Peter W » Tue, 17 Jun 1997 04:00:00



> > Please supply some more information about the data model and the
> > relevant linking fields.  Are you trying to recursively traverse a
> > single table that contains both parant & child records?  Are you
> > starting at the root and attempting to find all the leaves or at a leaf
> > and attempting to find the root?

> Actually, my data model, and even my structure is not what is in
> question at this point. It has come down to, why, as soon as I start to
> add code to a recursive algorithm, especially if I want to open a
> tcursor, does the available iterations drop down to an unusable level?

> Example:

> method Again(Level smallint)
>    Level = Level + 1
>    Message(Level)
>    if Level < 10000 then
>       Again(Level)
>    endif
> endMethod

> method run(var eventInfo Event)
>    Again(0)
> endMethod

> Using 7.0, Win95, the above iterates 9300 times before overflowing the
> stack. (It was 193 times with 5.0) If I declare a tcursor, the number
> drops to 5600, add 3 number variable declarations and I'm down to 4400,
> and I still haven't done anything.  In the real code I will be operating
> on at least 2 tcursors, possibly using arrays, setting ranges, scanning,
> making assignments, etc.  I've actually tried building some of the real
> code, and the overflow point had already dropped to 29 iterations.

> Our manufacturing structure requires tracking labor costs, s*rates,
> etc at every stage of the production process. There can be over a
> hundred processes to a finished product, each linked to the previous
> process and to the materials entered in at that process, This is
> basically a child table which references the parts included in its
> assembly, including other children listed in the same table,
> approximately thus:

> | Part* | PartLevel* | DetailPart* | DtlLevel* | Type | Qty |
>   C          1           B            2         S      1
>   C          1           X                      R      3
>   C          1           y                      R      1
>   B          2           B            1         S      1
>   B          2           Z                      R      1
>   B          1           W                      R      3
>   B          1           A            2         S      1
>   A          2           A            1         S      1
>   A          1           V                      R      10

> This reads as follows:  "S"ubPart A-1 is made from 10 of the "R"aw
> Material V, Then we do something to A-1 to make it into A-2 (machine it,
> for instance).  We now Make B-1 from the A-2 and 3 of W. We then add Z
> to B1 (and maybe machine this, or paint it, etc) to make it into B-2.
> We then add X and Y to B-2 to make C-1, which we then sell.

> This is a bit simplified, but it is accurate.  I need to be able to
> traverse this structure efficiently, passing the dtlPart to the
> recursive method so it will be treated as the "Part" within it.  I need
> to be able to do this from any point to any point, and to be able to
> rollup total quantities and costs for each end product.

> Since this is a pretty standard, if basic, MRP type structure, there has
> to be someone out there who has tried something like this with Paradox
> before.  (An SQL server is not an option, YET, and with Paradox as the
> front end, it may not help anyway.)

> I appreciate any input.

> Al Solter
> Primex Technologies
> Red Lion, PA

Al,

Five years ago we developed an MRP system with recursive processing in
Pdox 4.5 (Dos) which still works extremely well (and fast). About 1 1/2
years ago we we wrote a small system for rough cut capacity planning for
a chemical company and intended to use the same algorithm but had to
give up for the reasons you have found (although we were talking Pdox
4.5 / WFW at the time from memory).

I suggest you look at alternate algorithms. The beauty of the recursive
process is that it's neat and applicable anywhere. In our capacity
planning app it didn't take long to come up with an equivalent iterative
algorithm that sequentially passed through the table n + 1 times (n =
max no. of levels). This was fine because by definition we wanted to
process the whole file. You probably need several alternatives for your
different functions.

If I can help further please Email me.

Peter Wachtel

Databars Australia.

We still run a BOM processing system that w

 
 
 

Recursion - Bill of Materials

Post by Kasey Cha » Thu, 19 Jun 1997 04:00:00


On Fri, 13 Jun 1997 19:21:47 -0400, Al Solter

<asol...@worldnet.att.net> wrote:
>I have been blessed with the "opportunity" to design and develop an
>indented bill of materials for our company, to replace the flat file
>Vax/Cobol structures we have at present.  Most of the initial analysis
>is complete, and I have been experimenting with a few data models and
>algorithms.
>Recursion is the tool of choice for traversing this structure, and
>Paradox is not handling it very well.  5.0 under Win95 was not even
>worth talking about. 7.0 would have been alright if I didn't need to do
>anything more than count the iterations.

The FUN thing about recursion is it can be implemented without any
actual recursion by SIMULATING a stack!  I had the "honor" of dealing
with a recursive BOM myself. Glad that year of computer science
helped.

Here's the code, as a function I call from a library... It generates a
temporary table (GetTempFileName), traverses through the resursive
BOM, and pulls out all levels, filling in the level, whether the node
is an endnode or not, etc. Hope this may be of some help to someone.
No recursion involved, just a couple variables acting as "pointers".

uses Kernel
   GetTempFileName(Drive CWORD, PrefixString CPTR, Uniq CWORD, File
CPTR) CWORD
enduses

;-------------------------------------------------------
;Title: INF-LIB1.lsl::#Library1::FindPartBOM
;By: KASEYC
;Date: 02:18:43 PM, 02/13/96
;Syntax:
;Description:
;Usage:
;Notes:
;
;Modified by:
;Date:
;Reason:
;-------------------------------------------------------
;Error Constants

Const
   erIllegalPartName=1  ; Illegal PartName value
   erPartNameNotFound=2 ; Cannot find part name or no subpart in BOM
EndConst

method FindPartBOM2(var dbEE database, strPartName string, var
strTableName string) longint

var
;   db          database
   st,
   Item,
   Itemno,
   tFile,
   stPartClass,
   stPC2,
   parentpart,
   tstr        string
   s           sql
   q           query
   tc2,
   tcanswer,
   tcprior     tcursor
   t,
   level       smallint
   dbParm,
   dbParm2         dynarray [] anytype
   done        logical
   err            smallint
        fs                      FileSystem
        splitName       DynArray[] anytype
endvar

dbParm["USER NAME"]=""
dbParm["Password"]=""

dbParm2["USER NAME"]=""
dbParm2["Password"]=""

;if not db.open("INF_EE",dbParm) then
;   beep()
;   errorshow()
;   return errorcode()
;endif

dbParm.empty()
parentpart=""

tFile=fill(" ",144)
getTempFileName(0,"_PD",0,tFile)

; split file name into parts and store them in a DynArray

 splitFullFileName(tfile, splitName)

tfile=splitname["DRIVE"]+splitname["PATH"]+"_"+substr(splitname["NAME"],2,size(splitname["NAME"])-1)

Item=strPartName
parentpart=Item

If Item.isblank() or not Item.isAssigned() then
   beep()
   errorlog(UserError+erIllegalPartName,"Illegal PartName value!")
   errorshow()
;   db.close()
   return UserError+erIllegalPartName
endif

Item="\""+Item+"\""
Itemno=Item

st="select EBM.`EBM COMPITEM`,EBM.`EBM QTYPER`,1,0,ENB.`ENB
PARTCLASS`, ENB.`ENB COMMCODE`\N "+
", EBO.`EBO SCPPCT`,0,ENB.`ENB RESPENG`,ENB.`ENB MSGNO`,ENB.`ENB
PARTYPE`\n "+
", EBM.`EBM ITEMNO`,ENB.`ENB DESCRIP` \n "+
"from `EE EBM` EBM "+
"left outer join `EE ENB` ENB "+
"on EBM.`EBM COMPITEM`=ENB.`ENB ITEMNO` and EBM.`EBM DIV`=ENB.`ENB
DIV` "+
"left outer join `EE EBO` EBO "+
"on EBM.`EBM ITEMNO`=EBO.`EBO ITEMNO` and EBM.`EBM COMPITEM`=EBO.`EBO
COMPITEM` "+
"and EBM.`EBM DIV`=EBO.`EBO DIV` "+
"where EBM.`EBM DIV`=\"11\" and EBM.`EBM ITEMNO`="+Itemno

if not s.readfromstring(st) then
   beep()
   errorshow()
   err=errorcode()
;   db.close()
   return err
endif

sleep()

Try
  s.executeSQL(dbEE,tFile)
OnFail
  dbEE.close()
  dbEE.open("INF_EE",dbParm2)
  retry
Endtry

if not tcAnswer.open(tFile) then
   beep()
   errorshow()
   err=errorcode()
;   db.close()
   return err
endif

If tcAnswer.isempty() then
   msgstop("Error!","Part not found or no subparts found!")
   tcAnswer.close()
;   db.close()
   return userError+erPartNamenotFound
endif

tcAnswer.home()
tcAnswer.edit()
tcAnswer.empty()

;strPartName=Itemno

;first part found, writing initial record (level=0)
{st="select EBM.`EBM COMPITEM`,EBM.`EBM QTYPER`,1,0,ENB.`ENB
PARTCLASS`, ENB.`ENB COMMCODE`\N "+
", EBO.`EBO SCPPCT`,0,ENB.`ENB RESPENG`,ENB.`ENB MSGNO`,ENB.`ENB
PARTYPE`\n "+
", EBM.`EBM ITEMNO`,ENB.`ENB DESCRIP` \n "+}
st="select ENB.`ENB PARTCLASS`, ENB.`ENB COMMCODE`, EBO.`EBO
SCPPCT`,0"+
", ENB.`ENB RESPENG`,ENB.`ENB MSGNO`,ENB.`ENB PARTYPE` "+
", \"                              \",ENB.`ENB DESCRIP` \n "+
"from `EE ENB` ENB \n"+
"left outer join `EE EBO` EBO \n"+
"on ENB.`ENB DIV`=EBO.`EBO DIV` and ENB.`ENB ITEMNO`=EBO.`EBO ITEMNO`
\n"+
"where ENB.`ENB DIV`=\"11\" and ENB.`ENB ITEMNO`=\""+strPartName+"\""

if not s.readfromstring(st) then
   beep()
   errorshow()
   err=errorcode()
;   db.close()
   return err
endif

sleep()

if not s.executeSQL(dbEE,tc2) then
   beep()
   errorshow()
   return errorcode()
endif

tcAnswer.insertrecord(tc2)

tcAnswer."EBM COMPITEM"=strPartName
tcAnswer."EBM QTYPER"=1
tcAnswer."COLUMN3"="0"
tcAnswer."COLUMN4"="0"

tcAnswer."ENB PARTCLASS"=tc2."ENB PARTCLASS"
tcAnswer."ENB COMMCODE"=tc2."ENB COMMCODE"
tcAnswer."EBO SCPPCT"=tc2."EBO SCPPCT"
tcAnswer."COLUMN8"=0 ;column 8 is the # of Partclass
tcAnswer."ENB RESPENG"=tc2."ENB RESPENG"
tcAnswer."ENB MSGNO"=tc2."ENB MSGNO"
{tcAnswer."ENB PARTYPE"=tc2."
tcAnswer."ENB DESCRIP"=}
tcAnswer.unlockrecord()
tc2.close()

;parentpart=strPartName

;tcAnswer.nextrecord() ; skip first...

;initial record written, go through the rest...
done=false
while not done    ;not done yet?

   message("Processing:"+tcAnswer."EBM COMPITEM")
   level=tcAnswer."COLUMN3"
   Itemno="\""+tcAnswer."EBM COMPITEM"+"\""
   stPartClass=tcAnswer."ENB PARTCLASS"
        tcprior.attach(tcAnswer)

   parentpart=tcAnswer."EBM ITEMNO"

   if not isblank(tcAnswer."ENB PARTCLASS") then
      if not dbParm.contains(tcAnswer."ENB PARTCLASS") then
         dbParm[tcAnswer."ENB PARTCLASS"]=1
      else
         dbParm[tcAnswer."ENB PARTCLASS"]=dbParm[tcAnswer."ENB
PARTCLASS"]+1
      endif
      tcAnswer."COLUMN8"=dbParm[tcAnswer."ENB PARTCLASS"]
   else
      tcAnswer."COLUMN8"=0
   endif

   st="select EBM.`EBM COMPITEM`,EBM.`EBM QTYPER`,1,0,ENB.`ENB
PARTCLASS`, \n"+
   "ENB.`ENB COMMCODE`, EBO.`EBO SCPPCT`, 0,ENB.`ENB RESPENG`,ENB.`ENB
MSGNO`,ENB.`ENB PARTYPE` "+
   ",EBM.`EBM ITEMNO`,ENB.`ENB DESCRIP` \n "+
   "from `EE EBM` EBM \n"+
   "left outer join `EE ENB` ENB \n"+
   "on EBM.`EBM COMPITEM`=ENB.`ENB ITEMNO` and EBM.`EBM DIV`=ENB.`ENB
DIV` \n"+
   "left outer join `EE EBO` EBO \n"+
   "on EBM.`EBM ITEMNO`=EBO.`EBO ITEMNO` and EBM.`EBM
COMPITEM`=EBO.`EBO COMPITEM` "+
   "and EBM.`EBM DIV`=EBO.`EBO DIV` \n"+
   "where EBM.`EBM DIV`=\"11\" and EBM.`EBM ITEMNO`="+Itemno+" "

   if not s.readfromstring(st) then
      beep()
      errorshow()
      err=errorcode()
;      db.close()
      return errorcode()
   endif

   if not s.executeSQL(dbEE,tc2) then
      beep()
      errorshow()
      return errorcode()
   endif

   t=0

   if not tc2.isempty() then
   ;aha! I see subsparts!
      if not tcAnswer.edit() then
         beep()
         errorshow()
         return errorcode()
      endif
      tcAnswer."COLUMN4"=0
      tcAnswer.unlockrecord()
      ;tcAnswer.deleterecord()
      scan tc2:
         tcAnswer.insertafterrecord(tc2)
         tcAnswer."COLUMN3"=level+1
         tcAnswer."EBM QTYPER"=tcAnswer."EBM QTYPER"*tcprior."EBM
QTYPER"
         tstr=tcAnswer."ENB COMMCODE"
         if tstr.size()>3 and not stPartClass.isblank() then

            if substr(tstr,1,3)="LBL"{ and tcAnswer."ENB
PARTCLASS".isblank()} then
               tcAnswer."ENB PARTCLASS"=stPartClass+"L"
            endif
            if substr(tstr,1,3)="MED" and tcAnswer."ENB
PARTCLASS".isblank() then
                                if
stPartClass.substr(stPartClass.size())="X" then
                                        tcAnswer."ENB
PARTCLASS"=stPartClass.substr(1,stPartClass.size()-1)+"D"
                                else
                       tcAnswer."ENB PARTCLASS"=stPartClass+"D"
                                endif
            endif
            if substr(tstr,1,3)="SUB"{ and tcAnswer."ENB
PARTCLASS".isblank()} then
               tcAnswer."ENB PARTCLASS"=stPartClass+"X"
            endif
;           tcAnswer."COLUMN12"=parentpart
         endif
         if not tcAnswer.unlockrecord() then
            tcAnswer.updaterecord()
         endif
         t=t+1
      endscan
;     tcAnswer.endedit()
      while t>=1
         tcAnswer.priorrecord()
         t=t-1
      endwhile

   else
   ;no subparts, record as bottom, then next record
      if not tcAnswer.edit() then
         beep()
         errorshow()
         return errorcode()
      endif
      tcAnswer."COLUMN4"=1
      if not tcAnswer.unlockrecord() then
         tcAnswer.updaterecord()
      endif
;     tcAnswer."COLUMN12"=parentpart
;     tcAnswer.endedit()
   endif
;  tc2.close()

   if not tcAnswer.atlast() then
      tcAnswer.nextrecord()  
   else
      done=true
   endif
   tcprior.close()
endwhile

;--all right!  We're done!

tc2.close()
tcAnswer.unlockrecord()
tcAnswer.endedit()
tcanswer.close()

strTableName=tFile

return 0

endmethod

 
 
 

1. Bill of materials dimension hierarchy

Here's my problem - hopefully someone out there can help me with a
solution - it may be easier than I expected:

 I need to allow my end users to browse their store locations based on
several different groupings. Example: one grouping would contain all
stores (1
 -10). A separate grouping would include only acquired stores (1,2).
There also may be other groupings that I would let my users change (not
via
 OLAP) that could group stores into other groupings ("my favorite
stores"). Therefore, the problem is that one store could be a part of
MANY different
 groupings. Further, these grouping could reside WITHIN other groupings
- levels which may also contain individual stores as well. Think of the
 hierarchy as akin to how you can set up mail folders in a mail program
- a person can be in an "all" group, plus be in your private group. I
would like to
 be able to support this with my dimensions for my reporting.

 Using a parent-child dimension, supporting several groupings is
possible, but a store can only be a part of ONE GROUP (the child field
must contain
 unique values). This is not the solution. Any ideas?

2. java.lang.ClassNotFoundException : oracle.jdbc.driver.OracleDriver

3. my bills of materials

4. starting and stopping oracle

5. bill of material tree structure

6. pgsql-server/contrib/tablefunc/data

7. Bill of Materials Query

8. SQL Replication to MSDE

9. Bill of Materials - Parts Explosion

10. Bill of Material problem using annotated schemas

11. Bill of materials dimension hierarchy

12. Bill of Materials

13. Bill of Materials Database