【问题标题】:Oracle difficulty creating a procedure that has subqueryOracle 难以创建具有子查询的过程
【发布时间】:2021-10-11 23:57:02
【问题描述】:

我正在尝试构建一个将行插入到表 emp_attendance 中的过程。

我调用了一个基于范围生成日期列表的过程。然后我使用每个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 oracle subquery


    【解决方案1】:

    你没有提到序列,所以我删除了它。您的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.
    

    【讨论】:

    • 感谢您的帮助和专业知识。我想要 batch_id 并将添加该代码。 seq_num 应该是自动生成的。 SELECT into 我从来没有想过,但很高兴知道。非常感谢!!!
    【解决方案2】:

    在代码中读取 cmets。

    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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-05
      • 1970-01-01
      相关资源
      最近更新 更多