使用相同的密钥将多个 table 连接到一个基 table

Join multiple table to one base table using the same Keys

我目前正在为来自 Oracle 的大量财务报告编写 SQL 查询。此信息对于问题不是必需的,但可以提供一些背景信息:我基本上是从特定时间范围内获取所有 gl_JEs 并将它们分解为实际交易。

所以我生成了 6 个不同的子 table 和一个基础 table.

基础table包含生成PK的两个key和一些通用信息 Header_ID 和 Line_Num

每个子table 记录还包含这两个键和附加信息。 base table 和 subtable 之间可以存在一对多的关系。和一个基地的PK可以在多个subtables.

我想将这 6 个 table 连接在一起,保留基础的一般信息并添加子 table 的信息。我可以使用 Union ALL 来做到这一点,但这意味着我必须在每个子 table 上放置相同的字段,并且我必须加入很多字段,所以这不是最优的。

这里有一些示例数据,如果所有的讨论都没有意义的话。我将通过只有 3 个 sub tables:

来简化它
create table base (Header_id int,
                line_num int,
                period_num int);
create table subtable1 (header_id int,
                        line_num int,
                        cost    int,
                        description varchar(50));
create table subtable2 (header_id int,
                        line_num int,
                        invoice_num    int,
                        description varchar(50));
create table subtable3 (header_id int,
                        line_num int,
                        value    int,
                        description varchar(50));

Insert into base values
    (1, 1 , 4),
    (1,2,4),
    (2,5,4),
    (2,4,4),
    (3,1,4),
    (4,2,5);

Insert into subtable1 values
    (1, 1, 50, 'Boat'),
    (1, 1, 30, 'lifejacket'),
    (2, 4, 4000, 'lifeinsurance');
Insert into subtable2 values
    (1, 1, 89756, 'Boat supplies')
    (2,5, 5464, 'fake invoice');
Insert into subtable3 values
    (1, 2, 100, 'im running out')
    (3, 1, 25, 'of ideas');

我想要 return 这样的东西。请忽略我缺少 nulls/field 个名字

 1. 1,1,4,50,'BOAT'
 2. 1,1,4,30,'lifejacket' 
 3. 1,1,4,89756, 'boat supplies'
 4. 1,2,4,100,'im running out'
 5. 2,5,4,5464,'fake invoice'
 6. 2,4,4,4000,'lifeinsurance'
 7. 3,1,4,25,'of ideas'
 8. 4,2,5

有什么想法吗?

编辑:这是我现在的实际查询:

With 
base as 
    (
      SELECT 
           gjH.PERIOD_NAME Period
          ,gcc.SEGMENT1 || '-' || gcc.SEGMENT2 || '-' || gcc.SEGMENT3 || '-' || gcc.SEGMENT4 || '-' || gcc.SEGMENT5 || '-' || gcc.SEGMENT6 GL_COA
          ,gjL.JE_HEADER_ID
          ,gjL.JE_LINE_NUM
          ,gp.period_num
          ,gp.period_year
          ,gjh.date_created
          ,gjh.default_effective_date
          ,gjh.currency_code  base_currency_code
          ,gjh.currency_code  transaction_currency_code

      FROM
           apps.GL_JE_Batches         gjB
          ,apps.GL_JE_HEADERS         gjH
          ,apps.GL_JE_LINES           gjL
          ,apps.gl_code_combinations gcc
          ,apps.gl_periods            gp

      WHERE
              gjB.je_batch_id = gjH.JE_BATCH_ID
          and gjH.JE_HEADER_ID = gjL.JE_HEADER_ID
          and gjH.PERIOD_NAME in (:period, :period2, :period3)
          AND gjl.CODE_COMBINATION_ID = gcc.CODE_COMBINATION_ID
          and (gjL.accounted_dr != 0 OR gjL.accounted_cr != 0)
          and gjH.Period_Name = gp.Period_Name
      )
,Subledger as -- Not all Base records have a Subledger record! 58825
    ( -- Return all the primary keys for the Subledger and then the FK to the different distribution tables, 
      SELECT
           base.period Period
          ,base.GL_COA GL_COA
          ,base.JE_Header_ID
          ,base.JE_Line_NUM
          ,base.period_num
          ,base.period_year
          ,base.date_created
          ,base.default_effective_date
          ,base.base_currency_code
          ,base.transaction_currency_code
          ,xal.GL_SL_LINK_TABLE
          ,xal.GL_SL_LINK_ID
          ,xal.ae_line_num
          ,xah.ae_header_id
          ,xah.application_id
          ,xe.event_id
          ,xte.entity_id
          ,xdl.SOURCE_DISTRIBUTION_TYPE     --Tells you what table to pull lines/info from
          ,xdl.SOURCE_DISTRIBUTION_ID_NUM_1 --Is the FK ID to the above distribution table.
          ,decode(nvl(xdl.unrounded_accounted_dr,0),0,xdl.unrounded_accounted_cr,-1*xdl.unrounded_accounted_dr) base_amount
          ,decode(nvl(xdl.unrounded_accounted_dr,0),0,xdl.unrounded_accounted_cr,-1*xdl.unrounded_accounted_dr) transaction_amount

      FROM
           base
          ,apps.gl_import_references             gRef
          ,xla.xla_ae_lines                      xal
          ,xla.xla_ae_headers                    xah
          ,xla.xla_events                        xe
          ,xla.xla_transaction_entities          xte
          ,xla.xla_distribution_links            xdl
      WHERE

              base.JE_HEADER_ID        = gRef.JE_HEADER_ID
          AND base.JE_LINE_NUM         = gRef.JE_LINE_NUM
          AND gRef.GL_SL_LINK_TABLE   = xal.GL_SL_LINK_TABLE
          AND gRef.GL_SL_LINK_ID      = xal.GL_SL_LINK_ID
          and xal.AE_HEADER_ID        = xah.ae_header_id
          and xal.APPLICATION_ID      = xah.APPLICATION_ID
          and xah.AE_HEADER_ID = xdl.AE_HEADER_ID
          and xal.AE_LINE_NUM = xdl.AE_LINE_NUM
          and xah.event_id = xe.event_id
          and xah.application_id = xe.application_id
          and xe.entity_id = xte.entity_id
          and xe.APPLICATION_ID = xte.APPLICATION_ID
      )

,AP_PMT_DIST as --5476
    (
      SELECT
        sl.period
        ,sl.period_num
        ,sl.period_year
        ,sl.gl_coa
        ,sl.JE_Header_ID
        ,sl.JE_line_num
        ,sl.base_amount base_amount
        ,sl.transaction_amount transaction_amount
        ,'AP_PMT_DIST' || '|' || apid.description  description
        ,sl.date_created
        ,sl.default_effective_date
        ,sl.base_currency_code
        ,sl.Transaction_currency_code

      FROM
         subledger                                      sl
        ,AP.AP_PAYMENT_HIST_DISTS                       aphd
        ,AP.AP_INVOICE_DISTRIBUTIONS_ALL                apid

      WHERE
            sl.SOURCE_DISTRIBUTION_TYPE = 'AP_PMT_DIST'
        AND sl.SOURCE_DISTRIBUTION_ID_NUM_1 = aphd.payment_hist_dist_id
        and apid.invoice_distribution_id = aphd.invoice_distribution_id
    )
,AP_INV_DIST as --4422
    (
      SELECT
         sl.period
        ,sl.period_num
        ,sl.period_year
        ,sl.gl_coa
        ,sl.JE_header_id
        ,sl.je_line_num
        ,sl.base_amount base_amount
        ,sl.transaction_amount transaction_amount
        ,'AP_INV_DIST' || '|' || apid.description description
          ,sl.date_created
          ,sl.default_effective_date
        ,sl.base_currency_code
        ,sl.Transaction_currency_code
      FROM
        subledger                         sl
        ,AP.AP_INVOICE_DISTRIBUTIONS_ALL apid
      WHERE
              sl.SOURCE_DISTRIBUTION_TYPE = 'AP_INV_DIST'
          AND sl.SOURCE_DISTRIBUTION_ID_NUM_1 = apid.INVOICE_DISTRIBUTION_ID 
    )  
,AP_PREPAY as --10 records
    (
      SELECT
         sl.period
        ,sl.period_num
        ,sl.period_year
        ,sl.gl_coa
        ,sl.JE_header_id
        ,sl.je_line_num
        ,sl.base_amount base_amount
        ,sl.transaction_amount transaction_amount
        ,'AP_PREPAY' || '|' || apid.description description
          ,sl.date_created
          ,sl.default_effective_date
        ,sl.base_currency_code
        ,sl.Transaction_currency_code

      FROM
        subledger                         sl
        ,AP.AP_PREPAY_APP_DISTS           appad
        ,AP.AP_Invoice_distributions_all  apid
      WHERE
                sl.SOURCE_DISTRIBUTION_TYPE = 'AP_PREPAY'
                AND sl.SOURCE_DISTRIBUTION_ID_NUM_1 = appad.PREPAY_APP_DIST_ID
                AND appad.Invoice_distribution_id = apid.invoice_distribution_id
    )
,AR_DIST as --34321 records
    (
      SELECT
         sl.period
        ,sl.period_num
        ,sl.period_year
        ,sl.gl_coa
        ,sl.JE_header_id
        ,sl.je_line_num
        ,sl.base_amount base_amount
        ,sl.transaction_amount transaction_amount
        ,'AR Invoice Line' description
          ,sl.date_created
          ,sl.default_effective_date
        ,sl.base_currency_code
        ,sl.Transaction_currency_code
      FROM
        subledger                         sl
        ,AR.AR_DISTRIBUTIONS_ALL          ARDA
      WHERE
              sl.SOURCE_DISTRIBUTION_TYPE = 'AR_DISTRIBUTIONS_ALL'
          and sl.SOURCE_DISTRIBUTION_ID_NUM_1 = ARDA.line_id
    )
,AR_CUST_TRX as --14596 records
    (
      SELECT
         sl.period
        ,sl.period_num 
        ,sl.period_year
        ,sl.gl_coa
        ,sl.JE_header_id
        ,sl.je_line_num
        ,sl.base_amount base_amount
        ,sl.transaction_amount transaction_amount              
        ,'Cust_Trx_Line' description
          ,sl.date_created
          ,sl.default_effective_date
          ,sl.base_currency_code
          ,sl.transaction_currency_code

      FROM
        subledger                            sl
        ,AR.RA_CUST_TRX_LINE_GL_DIST_ALL     ctld
        ,AR.RA_Customer_trx_lines_all       ctl
      WHERE
              sl.SOURCE_DISTRIBUTION_TYPE = 'RA_CUST_TRX_LINE_GL_DIST_ALL'
          AND sl.source_distribution_id_num_1 = ctld.cust_trx_line_gl_dist_id
          AND ctld.customer_trx_line_id  = ctl.customer_trx_line_id (+)
          --and ctld.amount <> ctl.revenue_amount
    )
,spreads as
    (
      SELECT 
           b.PERIOD Period
          ,b.period_num
          ,b.period_year
          ,b.GL_COA
          ,b.JE_HEADER_ID
          ,b.JE_LINE_NUM
          ,decode(nvl(gjl.accounted_dr,0),0,gjl.accounted_cr,-1*gjl.accounted_dr)  base_amount
          ,decode(nvl(gjl.accounted_dr,0),0,gjl.accounted_cr,-1*gjl.accounted_dr)  transaction_amount
          ,gjH.DESCRIPTION DESCRIPTION
          ,b.date_created
          ,b.default_effective_date
          ,b.base_currency_code
          ,b.transaction_currency_code         


      FROM
           base                       B
          ,apps.GL_JE_HEADERS         gjH
          ,apps.GL_JE_LINES           gjL

      WHERE
              B.JE_Header_ID = gjH.JE_Header_ID
          AND B.JE_Line_Num = gjL.JE_Line_num    
          and gjH.JE_HEADER_ID = gjL.JE_HEADER_ID
          and gjH.JE_CATEGORY = 'Adjustment'
          and gjH.JE_SOURCE = 'Spreadsheet'
    )    
-- okay now we have all the types! and the number of records line up from the subledger distribution list.  
-- Now we need to get the required information about each transaction.
-- We will need to pass: Base table linking information (JEHeader and JELine) and Information about the line.
-- Then we will join these all together.
--Okay I have a breakdown, lets first get the values and make sure it all lines up.
  --select * from ar_cust_trx;
  --select * from AP_INV_DIST;


  SELECT * FROM AP_INV_DIST   AID --4422
  UNION ALL
  Select * FROM AP_PMT_DIST   APD  --9898 5476
  Union ALL
  select * FROM AP_PREPAY     APR --9908 10
  Union ALL
  select * FROM AR_DIST       ARD --44229 34321
  Union ALL 
  select * FROM AR_CUST_TRX   ARC --58825  It got rid of duplicates within itself, despite the fact they arn't duplicates.
  Union ALL
  select * FROM spreads --60011 1186

只需使用 UNION ALL - 大致如下:

SELECT DISTINCT * FROM 
(
        SELECT 
           base.header_id
           , base.line_num
           , base.period_num
           , subtable1.cost col3
           , subtable1.description col4
        FROM
           base 
           left join subtable1 
           on base.header_id = subtable1.header_id and base.line_num = subtable1.line_num

    UNION ALL

        SELECT 
           base.header_id
           , base.line_num
           , base.period_num
           , subtable2.invoice_num
           , subtable2.description
        FROM
           base 
           left join subtable2
           on base.header_id = subtable2.header_id and base.line_num = subtable2.line_num

    UNION ALL

         ...
)

我只是徒手写的,但我相信类似的东西应该可以解决问题。

希望对您有所帮助!!