从不同的表填充表

时间:2018-10-09 22:47:02

标签: sql oracle

美好的一天。

我有下表:

  • Order_Header(Order_id {pk},customer_id {fk},agent_id {fk},Order_date(DATE FORMAT))
  • Invoice_Header(Invoice_ID {pk},Customer_ID {fk},Agent_ID {fk},invoice_Date {DATE FORMAT})
  • 库存(Product_ID {pk},Product_description)

我创建了一个名为 AVG_COMPLETION_TIME_FACT 的表,并希望使用与前3个表有关的以下值填充该表:

  • 产品ID
  • 发票月
  • 发票年份
  • AVG_Completion_Time(发票日期-订单日期)

我有以下无效的代码:

    INSERT INTO AVG_COMPLETION_TIME_FACT(

SELECT PRODUCT_ID, EXTRACT (YEAR FROM INVOICE_DATE), EXTRACT (MONTH FROM INVOICE_DATE), (INVOICE_DATE - ORDER_DATE)
FROM STOCK, INVOICE_HEADER, ORDER_HEADER
GROUP BY PRODUCT_ID, EXTRACT (YEAR FROM INVOICE_DATE), EXTRACT (MONTH FROM INVOICE_DATE)
);

我想按product_id,发票年份和发票月份分组。

这可能吗?

任何建议将不胜感激。

致谢

1 个答案:

答案 0 :(得分:0)

简短的回答:有可能-如果您的数据库包含编写正确查询所需的更多列。

除了语法上的问题外,还有几个问题。当我们创建一些测试表时,您会发现所需的答案无法从问题中提供的列中得出。示例表(Oracle 12c),省略了所有PK / FK约束:

-- 3 tables, similar to the ones described in your question,
-- including some test data
create table order_header (id, customer_id, agent_id, order_date )
as
select 1000, 100, 1, date'2018-01-01' from dual union all
select 1001, 100, 2, date'2018-01-02' from dual union all
select 1002, 100, 3, date'2018-01-03' from dual
;

create table invoice_header ( id, customer_id, agent_id, invoice_date )
as
select 2000, 100, 1, date'2018-02-01' from dual union all
select 2001, 100, 2, date'2018-03-11' from dual union all
select 2002, 100, 3, date'2018-04-21' from dual
;

create table stock( product_id, product_description) 
as
select 3000, 'product3000' from dual union all
select 3001, 'product3001' from dual union all
select 3002, 'product3002' from dual
;

如果按照完成的方式联接表(使用交叉联接),则会看到比预期多的行...但是:invoice_header表和order_header表均不包含任何PRODUCT_ID数据。因此,我们无法确定哪些product_id与存储的order_id或invoice_id相关。

select 
  product_id
, extract( year from invoice_date )
, extract( month from invoice_date )
, invoice_date - order_date
from stock, invoice_header, order_header -- cross join -> too many rows in the resultset!
-- group by ...
;
...
27 rows selected.

为使查询正确,您可能应该编写INNER JOIN和条件(关键字:ON)。如果我们尝试使用您的原始表定义(如您的问题中所述)执行此操作,您将看到我们无法联接所有3个表,因为它们不包含所有需要的列:PRODUCT_ID(表STOCK)无法与ORDER_HEADER或INVOICE_HEADER。

这两个表(ORDER_HEADER和INVOICE_HEADER)的一个共同点是customer_id,但这不足以回答您的问题。但是,我们可以使用它来演示如何编写JOIN。

select 
  -- product_id
  IH.customer_id  as cust_id
, OH.id           as OH_id
, IH.id           as IH_id
, extract( year from invoice_date )  as year_
, extract( month from invoice_date ) as month_
, invoice_date - order_date          as completion_time
from invoice_header IH
  join order_header OH on IH.customer_id = OH.customer_id
-- the stock table cannot be joined at this stage
;

缺少列: 请将以下内容视为“概念验证”代码。假设在数据库中的某个地方,您的表中的列具有{1}链接STOCK和ORDER_HEADER(此处为STOCK_ORDER)和{2}链接ORDER_HEADER和INVOICE_HEADER(此处为ORDER_INVOICE),则实际上可以获取所需的信息。

-- each ORDER_HEADER is mapped to multiple product_ids
create table stock_order
as
select S.product_id, OH.id as oh_id  -- STOCK and ORDER_HEADER
from stock S, order_header OH ; -- cross join, we use all possible combinations here


select oh_id, product_id 
from stock_order 
order by OH_id 
;

PRODUCT_ID      OH_ID
---------- ----------
      3000       1000
      3000       1001
      3000       1002
      3001       1000
      3001       1001
      3001       1002
      3002       1000
      3002       1001
      3002       1002

9 rows selected.

-- each INVOICE_HEADER mapped to a single ORDER_HEADER
create table order_invoice ( order_id, invoice_id )
as
select 1000, 2000 from dual union all
select 1001, 2001 from dual union all
select 1002, 2002 from dual
; 

对于查询,请确保您编码了正确的JOIN条件(ON ...),例如

-- example query. NOTICE: conditions in ON ...
select 
  S.product_id
, IH.customer_id  as cust_id
, OH.id           as OH_id
, IH.id           as IH_id
, extract( year from invoice_date )  as year_
, extract( month from invoice_date ) as month_
, invoice_date - order_date          as completion_time
from invoice_header IH
  join order_invoice OI on IH.id = OI.invoice_id     -- <- new "link" table
  join order_header OH  on OI.order_id = OH.id  
  join stock_order SO   on OH.id = SO.OH_id          -- <- new "link" table
  join stock S          on S.product_id = SO.product_id 
;

现在,您可以添加GROUP BY,然后仅选择所需的列。与INSERT结合使用,您应该编写类似...

-- example avg_completion_time_fact table.  
create table avg_completion_time_fact (
  product_id number
, year_ number
, month_ number
, avg_completion_time number
) ;


insert into avg_completion_time_fact ( product_id, year_, month_, avg_completion_time )
select 
  S.product_id
, extract( year from invoice_date )  as year_
, extract( month from invoice_date ) as month_
, avg( invoice_date - order_date )   as avg_completion_time
from invoice_header IH
  join order_invoice OI on IH.id = OI.invoice_id
  join order_header OH  on OI.order_id = OH.id  
  join stock_order SO   on OH.id = SO.OH_id
  join stock S          on S.product_id = SO.product_id 
group by S.product_id, extract( year from invoice_date ), extract( month from invoice_date )  
;

AVG_COMPLETION_TIME_FACT表现在包含:

SQL> select * from avg_completion_time_fact order by product_id ;

PRODUCT_ID      YEAR_     MONTH_ AVG_COMPLETION_TIME
---------- ---------- ---------- -------------------
      3000       2018          3                  68
      3000       2018          4                 108
      3000       2018          2                  31
      3001       2018          3                  68
      3001       2018          2                  31
      3001       2018          4                 108
      3002       2018          3                  68
      3002       2018          4                 108
      3002       2018          2                  31

由于我们不知道数据库所包含的所有表的定义,因此尚不清楚数据库(或架构)的最终查询将是什么样。但是,如果应用这些技术并坚持使用示例的语法,则应该能够获得所需的结果。祝你好运!