【问题标题】:How to Duplicate multiple rows (Oracle)如何复制多行(Oracle)
【发布时间】:2012-05-14 14:38:50
【问题描述】:

我正在尝试创建一个过程,该过程将复制表的多行(或仅单行)并为每行插入递增 ID。

我的问题是,在我的过程中,我使用游标选择要复制的行,当我选择该游标中没有 WHERE 条件的所有行时,一切正常。 但是当我设置 WHERE 条件以仅选择一行时......什么也没有发生

这是我的程序

CREATE OR REPLACE PROCEDURE DuplicateEmployee (p_EmployeeID IN Employee.id%TYPE)
 AS
  p_New_EmployeeID Employee.id%TYPE;
  CURSOR c_DuplicateEmployee IS
    SELECT *
        FROM Employee
        WHERE Employee.id = p_EmployeeID; -- if this line is deleted all content is duplicated
  row_Employee c_DuplicateEmployee%ROWTYPE;
    BEGIN
      FOR myEmployee IN c_DuplicateEmployee LOOP
          p_New_EmployeeID := employee_seq.NEXTVAL;
          INSERT INTO Employee(id, first_name, last_name, start_date, end_date, salary, city, description)
            VALUES(p_New_EmployeeID, myEmployee.first_name, myEmployee.last_name, myEmployee.start_date, myEmployee.end_date, myEmployee.salary, myEmployee.city, myEmployee.description);
      END LOOP;
    COMMIT;
   END DuplicateEmployee;

我知道在这个示例中,选择要复制的主键的过程是没有意义的,但在我的生产基地中,它将用于选择外键。

下面是创建测试表和我用于此过程的序列所需的代码

CREATE TABLE Employee
  (
    ID         VARCHAR2(4 BYTE) NOT NULL,
    First_Name VARCHAR2(10 BYTE),
    Last_Name  VARCHAR2(10 BYTE),
    Start_Date DATE,
    End_Date DATE,
    Salary      NUMBER(8,2),
    City        VARCHAR2(10 BYTE),
    Description VARCHAR2(15 BYTE)
  );
INSERT
INTO Employee
    (ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
  VALUES
    ('01', 'Jason', 'Martin', to_date('19960725','YYYYMMDD'), to_date('20060725','YYYYMMDD'), 1234.56, 'Toronto', 'Programmer');
INSERT
INTO Employee
    (ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
  VALUES
    ('02', 'Alison', 'Mathews', to_date('19760321','YYYYMMDD'), to_date('19860221','YYYYMMDD'), 6661.78, 'Vancouver', 'Tester');
INSERT
INTO Employee
    (ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
  VALUES
    ('03', 'James', 'Smith', to_date('19781212','YYYYMMDD'), to_date('19900315','YYYYMMDD'), 6544.78, 'Vancouver', 'Tester');
INSERT
INTO Employee
    (ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
  VALUES
    ('04', 'Celia', 'Rice', to_date('19821024','YYYYMMDD'), to_date('19990421','YYYYMMDD'), 2344.78, 'Vancouver', 'Manager');
INSERT
INTO Employee
    (ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
  VALUES
    ('05', 'Robert', 'Black', to_date('19840115','YYYYMMDD'), to_date('19980808','YYYYMMDD'), 2334.78, 'Vancouver', 'Tester');
 INSERT
INTO Employee
    (ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
  VALUES
    ('06', 'Linda', 'Green', to_date('19870730','YYYYMMDD'), to_date('19960104','YYYYMMDD'), 4322.78, 'New York', 'Tester');
INSERT
INTO Employee
    (ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
VALUES
    ('07', 'David', 'Larry', to_date('19901231','YYYYMMDD'), to_date('19980212','YYYYMMDD'), 7897.78, 'New York', 'Manager');
INSERT
INTO Employee
    (ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
VALUES
    ('08', 'James', 'Cat', to_date('19960917','YYYYMMDD'), to_date('20020415','YYYYMMDD'), 1232.78, 'Vancouver', 'Tester');

此处用于管理主键 (ID) 的序列

CREATE SEQUENCE "TEST"."EMPLOYEE_SEQ" MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 1 NOCACHE ORDER NOCYCLE ;

这里是执行过程的代码

BEGIN
  employeepackage.duplicateemployee(5);
END;

我真的不明白为什么它在复制所有行时不能正常工作?少于 2 行的游标有限制吗?

任何帮助将不胜感激;)

【问题讨论】:

    标签: oracle plsql cursor


    【解决方案1】:

    为什么需要光标?您可以直接使用 SQL 执行此操作:

    INSERT INTO Employee(id, first_name, last_name, 
                         start_date, end_date, 
                         salary, city, description)
    SELECT employee_seq.NEXTVAL, e.first_name, e.last_name,
           e.start_date, e.end_date, 
           e.salary, e.city, e.description
    FROM Employee e
    WHERE e.id = p_EmployeeID;
    

    无论如何,实际问题是您的IDVARCHAR2(4),而您认为它是NUMBER。您实际上没有ID = 5 的员工,但您确实有ID = '05' 的员工。因此,无需更改任何内容,您的程序就已经可以工作了:

    BEGIN
      employeepackage.duplicateemployee('05');
    END;
    

    当然,更改ID的数据类型是有意义的。

    【讨论】:

    • 感谢如此快速的回答,我不知道我可以直接在 INSERT 语句中直接使用 sequence.NEXVAL!
    • @kwenji:还要检查documentation on the INSERT statement。您可以使用INSERT INTO .. SELECT 语法编写任意子查询...
    • 感谢 Lukas,我终于想起了我为什么使用游标,因为这个示例只是一个包的一部分,它将复制多个表的行并复制我需要提供父 ID 的元素的子元素。
    【解决方案2】:

    来自 Lukas 的解决方案,如果我的第一个和最后一个表不需要调用其他程序来复制多个孩子,但对于我使用的中间表:

    PROCEDURE Duplicate_Company (p_IdCity IN City.IdCity%TYPE) AS
    p_New_IdCompany Company.IdCompany%TYPE;
    CURSOR c_DuplicateCompany IS
    SELECT *
        FROM Company c
        WHERE c.IdCity = p_IdCity; 
    row_Company c_DuplicateCompany%ROWTYPE;
    BEGIN
      FOR c1 IN c_DuplicateCompany LOOP
          p_New_IdCompany := company_seq.NEXTVAL;
          INSERT INTO Company(IdCompany, IdCity, Name, CreationDate)
            VALUES(p_New_IdCompany, c1.IdCity, c1.Name, c1.CreationDate);
          -- Call the procedure to duplicate current employee
          Duplicate_Employee(c1.IdCompany);
      END LOOP;
    END Duplicate_Company;
    

    这是一个好方法吗?

    【讨论】:

      猜你喜欢
      • 2015-11-03
      • 2014-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-25
      • 1970-01-01
      • 2010-10-02
      • 1970-01-01
      相关资源
      最近更新 更多