Oracle 难以创建具有子查询的过程

Oracle difficulty creating a procedure that has subquery

我正在尝试构建一个将行插入 table emp_attendance.

的过程

我调用了一个根据范围生成日期列表的过程。然后我加入那个 table 和每个 employee_id.

作为新手 SQL 开发人员,我很难理解为什么没有创建过程 create_emp_attendance。

下面是我的测试案例。一旦我得到为 SELECT 工作的行,我将添加 INSERT 代码,因为我试图一次拿一小块。

在此先感谢您的帮助和专业知识。

     ALTER SESSION SET NLS_DATE_FORMAT = 'MMDDYYYY HH24:MI:SS';


    CREATE OR REPLACE TYPE nt_date IS TABLE OF DATE;
   

    CREATE OR REPLACE FUNCTION generate_dates_pipelined(
      p_from IN DATE,
      p_to   IN DATE
    )
    RETURN nt_date  PIPELINED   DETERMINISTIC
    IS
      v_start DATE := TRUNC(LEAST(p_from, p_to));
      v_end   DATE := TRUNC(GREATEST(p_from, p_to));
    BEGIN
     LOOP
        PIPE ROW (v_start);
        EXIT WHEN v_start >= v_end;
        v_start := v_start + INTERVAL '1' DAY;
      END LOOP;
      RETURN;
    END       generate_dates_pipelined;
   

    CREATE SEQUENCE batch_seq
      START WITH 1
      MAXVALUE 999999999999999999999999999
      MINVALUE 1
      NOCYCLE
     CACHE 20
     NOORDER;

      

    Create table employees(
      employee_id NUMBER(6), 
      first_name VARCHAR2(20),
      last_name VARCHAR2(20),
     card_num VARCHAR2(10),
      work_days VARCHAR2(7)
   );

    INSERT INTO employees (
     employee_id,
     first_name, 
     last_name,
     card_num,
     work_days
    )
    WITH names AS   ( 
      SELECT 1, 'John',     'Doe',      'D564311','YYYYYNN' FROM dual UNION ALL
      SELECT 2, 'Justin',     'Case',      'C224311','YYYYYNN' FROM dual UNION ALL
    SELECT 3, 'Mike',     'Jones',      'J288811','YYYYYNN' FROM dual UNION ALL
     SELECT 4, 'Jane',     'Smith',      'S564661','YYYYYNN' FROM dual 
   ) SELECT * FROM names; 


    CREATE TABLE  emp_attendance(    
  seq_num integer  GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
        employee_id NUMBER(6),
        start_date DATE,
        end_date DATE,
        week_number NUMBER(2),
        create_date DATE DEFAULT SYSDATE
        );

    CREATE OR REPLACE PROCEDURE create_emp_attendance      (
      p_start_date  IN DATE,
      p_end_date   IN DATE
    )
    IS  l_batch_seq number;
   BEGIN

        SELECT get_batch_seq INTO l_batch_seq FROM dual;

     SELECT 
      employee_id,
      start_date, 
      start_date+NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(3600,43200)), 'SECOND') AS end_date,
    to_char(start_date,'WW') AS week_number 

     FROM (
   
    -- Need subquery to generate end_date based on start_date. 

    SELECT 
    e.employee_id,         d.COLUMN_VALUE+       NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(0,86399)), 'SECOND') AS start_date
      FROM   employees e
       INNER JOIN TABLE(           generate_dates_pipelined(p_start_date, p_end_date)
       ) d
   ) ed
  END;


    EXEC create_emp_attendanc(DATE '2021-08-07', DATE '2021-08-14');

阅读代码中的注释。

SQL> CREATE OR REPLACE PROCEDURE create_emp_attendance
  2   (
  3    p_start_date  IN DATE,
  4    p_end_date   IN DATE
  5   )
  6  IS
  7    l_batch_seq number;
  8  BEGIN
  9    -- there's no GET_BATCH_SEQ function (at least, you didn't post it)
 10    -- SELECT get_batch_seq INTO l_batch_seq FROM dual;
 11    l_batch_seq := batch_seq.nextval;
 12
 13    -- In order to avoid TOO_MANY_ROWS, switching to a cursor FOR loop
 14    for cur_r in
 15     (SELECT
 16        employee_id,
 17        start_date,
 18        start_date+NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(3600,43200)), 'SECOND') AS end_date,
 19        to_char(start_date,'WW') AS week_number
 20      FROM (-- Need subquery to generate end_date based on start_date.
 21            SELECT
 22              e.employee_id,
 23              d.COLUMN_VALUE + NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(0,86399)), 'SECOND') AS start_date
 24            FROM   employees e
 25            -- not INNER, but CROSS join (or, if it were INNER, on which column(s)?)
 26            CROSS JOIN TABLE(generate_dates_pipelined(p_start_date, p_end_date)) d
 27           ) ed
 28           ) loop
 29        -- you'll probably have INSERT statement here, according to what you said
 30        null;
 31      end loop;
 32  END;
 33  /

Procedure created.

测试:

SQL> EXEC create_emp_attendance(DATE '2021-08-07', DATE '2021-08-14');

PL/SQL procedure successfully completed.

SQL>

你没有提到序列,所以我删除了它。您的 SELECT 需要通过 INTO 子句具有目标或在 INSERT(或其他)语句的上下文中使用。 JOIN 缺少 ON 子句。但是你似乎想要 CROSS JOIN.

如果您真的想 INSERT 在一条语句中,请使用以下形式:

CREATE OR REPLACE PROCEDURE create_emp_attendance      (
      p_start_date  IN DATE,
      p_end_date    IN DATE
    )
    IS
   BEGIN
     INSERT INTO emp_attendance (employee_id, start_date, end_date, week_number)
     SELECT employee_id
          , start_date
          , start_date+NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(3600,43200)), 'SECOND') AS end_date
          , to_char(start_date,'WW') AS week_number 
     FROM (  -- Need subquery to generate end_date based on start_date. 
             SELECT e.employee_id, d.COLUMN_VALUE + NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(0,86399)), 'SECOND') AS start_date
               FROM   employees e
              CROSS JOIN TABLE( generate_dates_pipelined(p_start_date, p_end_date) ) d
          ) ed
          ;
END;
/

EXEC create_emp_attendance(DATE '2021-08-07', DATE '2021-08-14');
/

-- Procedure CREATE_EMP_ATTENDANCE compiled
-- PL/SQL procedure successfully completed.