未找到父键(oracle)

时间:2016-12-18 10:54:22

标签: oracle

我想使用oracle过程将400000个随机行插入到表中。

我收到了'违规 - 未找到父密钥'错误。

create or replace 
PROCEDURE TESTDATA AS 
X INTEGER;
BEGIN
  FOR X IN 1..400000 LOOP
    INSERT INTO SALES 
    SELECT CAST(DBMS_RANDOM.VALUE(1, 10) as INTEGER) as "CUSTOMER_ID",
    CAST(DBMS_RANDOM.VALUE(1, 2) as INTEGER) as "PRODUCT_ID",
    TO_DATE(TRUNC(DBMS_RANDOM.VALUE(TO_CHAR(TO_DATE('1-jan-2000'),'J'),TO_CHAR(TO_DATE('21-dec-2012'),'J'))),'J') as "SALES_DATE",
    CAST(DBMS_RANDOM.VALUE(1, 100) as INTEGER) as "PIECES"
    FROM  DUAL;
  END LOOP;
END TESTDATA;


-- -----------------------------------------------------
-- Table SALES
-- -----------------------------------------------------
CREATE TABLE SALES (
  CUSTOMER_ID INTEGER,
  PRODUCT_ID INTEGER,
  SALES_DATE DATE,
  PIECES INTEGER,
  PRIMARY KEY (CUSTOMER_ID, PRODUCT_ID, SALES_DATE),
  FOREIGN KEY (CUSTOMER_ID) REFERENCES CUSTOMER (CUSTOMER_ID),
  FOREIGN KEY (PRODUCT_ID) REFERENCES PRODUCT (PRODUCT_ID)
);

我希望有人能帮助我。

罗马

Table customer

Table product

1 个答案:

答案 0 :(得分:-1)

您的create table声明包含CUSTOMER和PRODUCT表格中的外键。您的insert语句使用随机值来填充CUSTOMER_ID和PRODUCT_ID。随机值极不可能与引用表中的现有键匹配,因此您会发现外键违规并不足为奇。

关于你如何修复它,这取决于你真正想要实现的目标。当您使用随机数填充表时,您显然不关心数据,因此您可以删除外键。或者,您可以使用insert语句中引用的表中的主键值。

  

“如何使用引用表中的主键值?”

您有二十种产品和客户的排列。因此,您需要将它们颠簸20000次以生成400000条记录。

  

“在客户表中我插入了10行(1-10),在产品表中插入了2行(1-2)”

这是您的程序的一个版本,它循环通过产品和客户来生成它们的随机组合。还有第三个外环,可以让你根据自己的心愿生成20组连组合。

create or replace procedure testdata 
    ( p_iters in pls_integer := 1)
as 
  type sales_nt is table of sales%rowtype;
  recs sales_nt;
  rec sales%rowtype;
  tot_ins simple_integer := 0;
begin
  recs := new sales_nt();
  dbms_random.seed(val=>to_number(to_char(sysdate,'sssss')));
  << iterz >>
  for idx in 1..p_iters loop
    << prodz >>
    for c_rec in ( select customer_id from customer
                   order by dbms_random.value )
    loop
      << custz >>
      for p_rec in ( select product_id from product
                       order by dbms_random.value )
      loop
        rec.customer_id := c_rec.customer_id;
        rec.product_id := p_rec.product_id;
        rec.sales_date := date '2000-01-01' + dbms_random.value(1, 6000);
        rec.pieces := dbms_random.value(1, 100);
        recs.extend();
        recs(recs.count()) := rec;
      end loop custz;
    end loop prodz;
    forall idx in 1..recs.count()
      insert into sales
      values recs(idx);
    tot_ins := tot_ins + sql%rowcount;
    recs.delete();
  end loop iterz;
  dbms_output.put_line('test records generated = '||to_char(tot_ins));
end testdata;
/

布丁证明:

SQL> set serveroutput on
SQL> exec testdata(2)
test records generated = 40

PL/SQL procedure successfully completed.

SQL> select * from sales;

CUSTOMER_ID PRODUCT_ID SALES_DAT     PIECES
----------- ---------- --------- ----------
          9          2 21-FEB-02         42
          9          1 10-AUG-05         63
          7          1 23-FEB-12         54
          7          2 21-NOV-12         80
          1          2 06-NOV-15         56
          1          1 08-DEC-09         47
          4          2 08-JUN-10         58
          4          1 19-FEB-09         43
          2          2 04-SEP-02         64
          2          1 09-SEP-15         69
          6          2 20-FEB-08         60

...

          2          1 11-JAN-16         19
          3          2 03-FEB-10         58
          3          1 25-JUL-10         66
          9          2 26-FEB-16         70
          9          1 15-MAY-14         90
          6          2 03-APR-05         60
          6          1 21-MAY-15         19

40 rows selected.

SQL> 

注释

正如@mathguy所指出的,OP的代码约束了随机值的范围,以适应引用表中主键的范围。但是,我会留下这个答案,因为它的一般方法既安全(保证始终匹配引用的主键)又不那么脆弱(可以处理插入或删除PRODUCT或CUSTOMER记录。