2

I'm working with my DBA to try to figure out a way to roll up all costs associated with a Work Order. Since any work Order can have multiple child work orders (through multiple "generations") as well as related work orders (through the RELATEDRECORDS table), I need to be able to get the total of the ACTLABORCOST and ACTMATERIALCOST fields for all child and related work orders (as well as each of their child and related work orders). I've worked though a hierarchical query (using CONNECT BY PRIOR) to get all the children, grandchildren, etc., but I'm stuck on the related work orders. Since every work order can have a related work order with it's own children and related work orders, I need an Oracle function that drills down through the children and the related work orders and their children and related work orders. Since I would think that this is something that should be fairly common, I'm hoping that there is someone who has done this and can share what they've done.

Frank Ball
  • 1,039
  • 8
  • 15
  • There are 2 options in Oracle to solve that. One using Oracle's Connect by (which you mentioned already), and another by using Recursive Subquery Factoring. In order to provide better assistance to you it would be great if you could provide a simplified version of your data structure, sample data and expected results. That way someone will likely be able to tailor a solution that works for your problem as opposed to make suggestions that may or may not apply to what you need. – Francisco Sitja Jul 17 '19 at 20:49
  • Connect by: https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/Hierarchical-Queries.html#GUID-E3D35EF7-33C3-4D88-81B3-00030C47AE56 Recursive Subquery Factoring: https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6 – Francisco Sitja Jul 17 '19 at 20:51
  • Are you planning to use the results inside or outside Maximo? – Preacher Jul 18 '19 at 14:23

3 Answers3

1

Have you considered the WOGRANDTOTAL object? Its description in MAXOBJECT is "Non-Persistent table to display WO grandtotals". There is a dialog in the Work Order Tracking application that you can get to from the Select Action / More Actions menu. Since you mentioned it repeatedly, I should note that WOGRANDTOTAL values do not include joins across RELATEDRECORDS to other work order hierarchies.

You can also save yourself the complication of CONNECT BY PRIOR by joining to WOANCESTOR, which is effectively a dump from a CONNECT BY PRIOR query. (There are other %ANCESTOR tables for other hierarchies.)

I think a recursive automation script would be the best way to do what you want, if you need the results in Maximo. If you need the total cost outside of Maximo, maybe a recursive function would work.

Preacher
  • 2,127
  • 1
  • 11
  • 25
  • The whole picture is that we have some internal software we use for tracking safety incidents and need to know the full cost to the company of an incident (this is related to property damage). We're working on a recursive function to this, but my hope is that there is someone who has already invented this wheel who can share that work. I've looked at the WOGRANDTOTAL function and because it doesn't handle the RELATEDRECORDS, it won't work for us by itself. – Frank Ball Jul 18 '19 at 14:33
  • As far as I've seen in 14 years, people don't care about summing across RELATEDRECORDS / across hierarchies. So, there may not be many who have invented this wheel before. – Preacher Jul 18 '19 at 14:41
1

Another option would be a recursive query, as suggested by Francisco Sitja. Since my Oracle didn't allow 2 UNION ALLs, I had to joint to the WOANCESTOR table in both child queries instead of dedicating a UNION ALL for doing the WO hierarchy. I was then able to use the one permitted UNION ALL for doing the RELATEDRECORD hierarchy. And it seems to run pretty quickly.

with mywos (wonum, parent, taskid, worktype, description, origrecordid, woclass, siteid) as (
    -- normal WO hierarchy
    select wo.wonum, wo.parent, wo.taskid, wo.worktype, wo.description, wo.origrecordid, wo.woclass, wo.siteid
    from woancestor a
        join workorder wo
            on a.wonum = wo.wonum
            and a.siteid = wo.siteid
    where a.ancestor = 'MY-STARTING-WONUM'
    union all
    -- WO hierarchy associated via RELATEDRECORD
    select wo.wonum, wo.parent, wo.taskid, wo.worktype, wo.description, wo.origrecordid, wo.woclass, wo.siteid
    from mywos
        join relatedrecord rr
            on mywos.woclass = rr.class
            and mywos.siteid = rr.siteid
            and mywos.wonum = rr.recordkey
            -- prevent cycle / going back up the hierarchy
            and rr.relatetype not in ('ORIGINATOR')
        join woancestor a
            on rr.relatedrecsiteid = a.siteid
            and rr.relatedreckey = a.ancestor 
        join workorder wo
            on a.siteid = wo.siteid
            and a.wonum = wo.wonum
)
select * from mywos
;
Preacher
  • 2,127
  • 1
  • 11
  • 25
  • We ended up with a similar (and simpler) approach. Our learning curve was figuring out how to make the "WITH" work. – Frank Ball Jul 19 '19 at 17:48
  • I've a taken a closer look at your statement and I see where yours is getting all the levels out. One thing is that both our statements can return duplicates, so your final statement needs to be a "SELECT DISTINCT". – Frank Ball Jul 22 '19 at 15:48
  • Also, why use the WOANCESTOR table instead of using "CONNECT BY PRIOR"? (just trying to get a better understanding) – Frank Ball Jul 22 '19 at 15:49
  • I was looking through some of my early attempts at this and I was getting a lot of "CYCLE" errors The 2nd one I tried was almost identical to yours but without the "relatetype not in ('ORIGINATOR')" clause and using CONNECT BY PRIOR.instead of WOANCESTOR. – Frank Ball Jul 22 '19 at 16:15
  • 1
    Thanks for catching the DISTINCT problem. The ANCESTOR tables (WOANCESTOR, LOCANCESTOR, etc) are basically saved results of CONNECT BY. They are narrow tables and typically indexed, so should perform better than CONNECT BY PRIOR, which has to figure everything out all over again every time. – Preacher Jul 23 '19 at 19:41
0

We finally figured out how to pull this off.

WITH WO(WONUM,
PARENT) AS
((SELECT X.WONUM,
                  X.PARENT
        FROM (SELECT R.RECORDKEY WONUM,
                                    R.RELATEDRECKEY PARENT
                        FROM MAXIMO.RELATEDRECORD R
                        WHERE R.RELATEDRECKEY = '382418'
                    UNION ALL
                    SELECT W.WONUM,
                                    W.PARENT
                        FROM MAXIMO.WORKORDER W
                        START WITH W.PARENT = '382418'
                    CONNECT BY PRIOR W.WONUM = W.PARENT) X) 
           UNION ALL 
  SELECT W.WONUM, W.PARENT FROM MAXIMO.WORKORDER W, WO WHERE W.WONUM = WO.PARENT)
SELECT DISTINCT WONUM FROM WO;

This returns a list of all of the child and related work orders for a given work order.

Frank Ball
  • 1,039
  • 8
  • 15
  • It will only find them if your starting work order has a follow-up, and it will only search out (across RELATEDRECORD) once. – Preacher Jul 19 '19 at 18:01
  • I'm revising my opinion. Your inline view returns 1 level out plus all levels down. Then your `with` uses that to go down again. So, you'll get from `'382418'` and down plus one level out and down. But your original requirement was to go all the way out (however many levels) and down all, which I think my query achieves. – Preacher Jul 19 '19 at 18:24