views:

296

answers:

3

Hello,

I'm hoping someone can help me as I've been stuck on this problem for a few days now. Basically I'm trying to pull data from 3 tables in Oracle: 1) Orders Table 2) Vendor Table and 3) Master Data Table.

Here's what the 3 tables look like:

Table 1: BIZ_DOC2 (Orders table)

OBJECTID (Unique key)
UNIQUE_DOC_NAME (Document Name i.e. ORD-005)
CREATED_AT (Date the order was created)

Table 2: UDEF_VENDOR (Vendors table):

PARENT_OBJECT_ID (This matches up to the OBJECTID in the Orders table)
VENDOR_OBJECT_NAME (This is the name of the vendor i.e. Acme)

Table 3: BIZ_UNIT (Master Data table)

PARENT_OBJECT_ID (This matches up to the OBJECTID in the Orders table)
BIZ_UNIT_OBJECT_NAME (This is the name of the business unit i.e. widget A, widget B)

Note: The Vendors Table and Master Data do not have a link between them except through the Orders table.

I can join all of the data from the tables and it looks something like this:

Before selecting latest order date:

ORD-005 | Widget A | Acme | 3/14/10
ORD-005 | Widget B | Acme | 3/14/10
ORD-004 | Widget C | Acme | 3/10/10

Ideally I'd like to return the latest order for each vendor. However, each order may contain multiple business units (e.g. types of widgets) so if a Vendor's latest record is ORD-005 and the order contains 2 business units, here's what the result set should look like by the following columns: UNIQUE_DOC_NAME, BIZ_UNIT_OBJECT_NAME, VENDOR_OBJECT_NAME, CREATED_AT

After selecting by latest order date:

ORD-005 | Widget A | Acme | 3/14/10
ORD-005 | Widget B | Acme | 3/14/10

I tried using Select Max and several variations of sub-queries but I just can't seem to get it working. Any help would be hugely appreciated!

+1  A: 
SELECT
  O.UNIQUE_DOC_NAME,
  U.BIZ_UNIT_OBJECT_NAME,
  V.VENDOR_OBJECT_NAME,
  O.CREATED_AT
 FROM
  ( SELECT
      V.VENDOR_OBJECT_NAME, MAX(O.CREATED_AT) AS CREATED_AT
     FROM
      UDEF_VENDOR AS V
     INNER JOIN
      BIZ_DOC2 AS O
     ON
      V.PARENT_OBJECT_ID=O.OBJECTID
     GROUP BY
      V.VENDOR_OBJECT_NAME
  ) AS VO   -- most recent order date per vendor
 INNER JOIN
  UDEF_VENDOR AS V
 ON
  V.VENDOR_OBJECT_NAME=VO.VENDOR_OBJECT_NAME
 INNER JOIN
  BIZ_DOC2 AS O
 ON         -- re-match vendors to orders for latest date
  O.OBJECTID=V.PARENT_OBJECT_ID AND
  O.CREATED_AT=VO.CREATED_AT
 INNER JOIN
  BIZ_UNIT AS U
 ON
  U.PARENT_OBJECT_ID=O.OBJECTID
vladr
Hi Vlad, wow that was quick! Thanks so much for the solution. I'll try it out now and let you know if it works ok. Thanks! :)
Nancy
Hi Vlad, this is strange but I'm getting an Oracle ORA-00907: missing right parenthesis error even though there are no missing parenthesis in your code. I've double and triple checked everything... any idea what the issue could be? Thanks again for your help!
Nancy
Hmmm, parses fine over here... have you tried removing the comments?
vladr
Disregard my last post as I got your query working by removing the 'AS' before every alias name and it worked like a charm! Huge thanks again for the help! :)
Nancy
+2  A: 
SELECT DISTINCT
       FIRST_VALUE(d.unique_doc_name)
       OVER (PARTITION BY v.vendor_object_name
             ORDER BY d.created_at DESC)
       AS unique_doc_name
      ,FIRST_VALUE(u.biz_unit_object_name)
       OVER (PARTITION BY v.vendor_object_name
             ORDER BY d.created_at DESC)
       AS biz_unit_object_name
      ,FIRST_VALUE(v.vendor_object_name)
       OVER (PARTITION BY v.vendor_object_name
             ORDER BY d.created_at DESC)
       AS vendor_object_name
      ,FIRST_VALUE(d.created_at)
       OVER (PARTITION BY v.vendor_object_name
             ORDER BY d.created_at DESC)
       AS created_at
FROM   biz_doc2 d, udef_vendor v, biz_unit u
WHERE  d.objectid = v.objectid
AND    d.objectid = u.parent_object_id;
Jeffrey Kemp
Hi Jeff, thanks for your answer! I got the first one working alrady but I'll definitely try yours answer too. I hadn't considered the PARTITION BY function so I'll give it a go. Thanks! :)
Nancy
This query has the advantage that it only requires one pass through the table. It has the disadvantage that it only reports one row if there is more than one record with the latest created_at for a vendor.
Jeffrey Kemp
Hi Jeff, I tried your query too and it worked! Yes I see what you mean about how it only returns one record if two were created on the same date for the same Vendor. I'll have a think about it but will up-vote your answer for now since it works. Many thanks again!
Nancy
A: 

Here's another solution using analytic functions. Instead of getting the first value for the max date, it ranks the dates and gets all values for the latest date.

select unique_doc_name, biz_unit_object_name, vendor_object_name, created_at
from (select unique_doc_name, biz_unit_object_name,
             vendor_object_name, created_at,
             rank () over (order by created_date desc) rnk
      from biz_doc2 d, udef_vendor v, biz_unit u
      where d.object_id = v.parent_object_id
      and d.objectid = u.parent_object_id)
where rnk = 1;
Allan
Hi Allan, thanks for your help! :) I'll try it out to see if I can get it working. Many thanks!
Nancy