sqloracle-database

Oracle SQL - Recursive Query?


I am attempting to write a query that will return a distinct count of order numbers where the part (and then corresponding parts) can be found.

Columns: ORDER_NO     PART_NO      AMOUNT
         A            1            10
         B            1            10
         B            1            15
         B            2            10
         C            2            20
         D            3            30
         E            3            10
         F            4            10

Search 1: Part 1, Expected Count 3

Part 1 exists in 2 orders (A/B), but on order B, part 2 also exists, so find any order where part 2 exists too (Which therefore includes order C)

Search 2: Part 2, Expected Count 3

Part 2 exists in 2 orders (B/C), but on order B, part 1 also exists, so find any order where part 1 exists too (Which therefore includes order A)

Search 3: Part 3, Expected Count 2

Part 3 only exists on 2 orders (D/E)

Search 4: Part 4, Expected Count 1

Part 4 only exists on 1 order (F)


Furthermore I am also looking to SUM the AMOUNT as well (Using Maximum AMOUNT Order, regardless of PART_NO)

Using the searches above:

Search 1: AMOUNT = 45 (10 from A, Max 15 from B, 20 from C)

Search 2: AMOUNT = 45 (Max 15 from B, 10 from A, 20 from C)

Search 3: AMOUNT = 40 (30 from D, 10 from E)

Search 4: AMOUNT = 10 (10 from F)


Solution

  • You can use a hierarchical query connecting by either order_no or part_no and then finding the MAXimum number of parts for each order_no and then aggregating to find the total over the entire result set:

    SELECT SUM(MAX(amount)) AS total
    FROM   employee
    START WITH part_no = :part_no
    CONNECT BY NOCYCLE
           PRIOR part_no = part_no
    OR     PRIOR order_no = order_no
    GROUP BY order_no
    

    Which, for the sample data:

    CREATE TABLE employee (ORDER_NO, PART_NO, AMOUNT) AS
    SELECT 'A', 1, 10 FROM DUAL UNION ALL
    SELECT 'B', 1, 10 FROM DUAL UNION ALL
    SELECT 'B', 1, 15 FROM DUAL UNION ALL
    SELECT 'B', 2, 10 FROM DUAL UNION ALL
    SELECT 'C', 2, 20 FROM DUAL UNION ALL
    SELECT 'D', 3, 30 FROM DUAL UNION ALL
    SELECT 'E', 3, 10 FROM DUAL UNION ALL
    SELECT 'F', 4, 10 FROM DUAL;
    

    If :part_no is 1 or 2 then the output is:

    TOTAL
    45

    If :part_no is 3 then the output is:

    TOTAL
    40

    If :part_no is 4 then the output is:

    TOTAL
    10

    fiddle