【问题标题】:Oracle procedure inserting multiple rows from result of queryOracle过程从查询结果中插入多行
【发布时间】:2021-10-03 15:31:04
【问题描述】:

我正在尝试创建一个过程,该过程将根据过程中的查询结果将多行插入到表中。

下面的设置工作正常,但我很难将查询输出中的employee_id、timeoff_date 插入到timeoff 表中。

以下是我的测试用例。我正在实时 sql 中进行测试,所以我们都可以拥有相同的 Oracle 版本。任何帮助将不胜感激。

    CREATE OR REPLACE TYPE obj_date IS OBJECT (
     date_val DATE
    );

      CREATE OR REPLACE TYPE nt_date IS TABLE OF obj_date;


    create or replace function generate_dates_pipelined(
            p_from  in date,
            p_to    in date
   )
      return nt_date 
      pipelined
      is
      begin
        for c1 in (
            with calendar (start_date, end_date ) as (
                    select trunc(p_from), trunc(p_to) from dual
                    union all
                    select start_date + 1, end_date
                    from   calendar
                    where  start_date + 1 <= end_date
            )
            select start_date as day
            from   calendar
    ) loop
            pipe row (obj_date(c1.day));
    end loop;

    return;
   end         generate_dates_pipelined;

   create table holidays(
      holiday_date DATE not null,
     holiday_name VARCHAR2(20),
     constraint holidays_pk primary key (holiday_date),
     constraint is_midnight check ( holiday_date = trunc ( holiday_date ) )
    );

    INSERT into holidays (HOLIDAY_DATE,HOLIDAY_NAME) WITH dts as (
          select to_date('01-AUG-2021 00:00:00','DD-MON-YYYY HH24:MI:SS'), 'August  1st 2021' from dual union all
         select to_date('05-AUG-2021 00:00:00','DD-MON-YYYY HH24:MI:SS'), 'August  5th 2021' from dual)   SELECT * from dts;


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


     ALTER TABLE employees
             ADD ( CONSTRAINT employees_pk
           PRIMARY KEY (employee_id));

   INSERT INTO employees                   
 (
EMPLOYEE_ID,
first_name, 
last_name,
card_num,
work_days)
   WITH names AS ( 
   SELECT 1, 'Jane',     'Doe','F123456', 'NYYYYYN'   FROM dual UNION ALL 
    SELECT 2, 'Madison', 'Smith','R33432','NYYYYYN'FROM dual UNION ALL 
    SELECT 3, 'Justin',   'Case','C765341','NYYYYYN'FROM dual UNION ALL 
    SELECT 4, 'Mike',     'Jones',      'D564311','NYYYYYN' FROM dual) SELECT * FROM names;  

create table timeoff(
         seq_num integer  GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
    employee_id NUMBER(6),
    timeoff_date DATE,
    timeoff_type VARCHAR2(1) DEFAULT 'V',
     constraint timeoff_chk check (timeoff_date=trunc(timeoff_date, 'dd')),
      constraint timeoff_pk primary key (employee_id, timeoff_date)
     );

   CREATE OR REPLACE PROCEDURE create_timeoff_requests (start_date DATE, end_date DATE)
   IS
    type t_date is table of date;
     l_res t_date;
     BEGIN

  SELECT 
 c.date_val
 BULK COLLECT INTO l_res
 FROM   employees e
  INNER JOIN  TABLE (generate_dates_pipelined (start_date, end_date))c
PARTITION BY ( e.employee_id )
        ON (SUBSTR(e.work_days, TRUNC(c.date_val) - TRUNC(c.date_val, 'IW') + 1, 1) = 'Y')
WHERE  NOT EXISTS (
 SELECT 1
        FROM   holidays h
        WHERE  c.date_val = h.holiday_date
       )
ORDER BY
    e.employee_id,
     c.date_val;

      -- debug
      --  for i in 1..l_res.count -- loop
            --dbms_output.put_line(l_res(i));
    --      end loop;   
    END;

       EXEC create_timeoff_requests (DATE '2021-08-01', DATE '2021-08-10');

【问题讨论】:

  • 需要在表格中插入l_res的内容吗?
  • No I_res 只有日期。在 not EXISTS 逻辑之后连接的所有行。这就是我想要插入的。我尝试使用代码中的 SELECT 提供的 INSERT 语句修改我的代码

标签: sql oracle plsql-package


【解决方案1】:

我认为创建一个看起来像这样的过程可能更容易(只需将块中声明的常量替换为过程定义中的参数):

CREATE PROCEDURE create_timeoff_requests
(
  p_dStart DATE,
  p_dEnd DATE,
  p_nEmployeeID INTEGER
  p_sType VARCHAR2
)
IS
BEGIN
  INSERT INTO timeoff (employee_id, timeoff_date, timeoff_type)
    SELECT e.employee_id, do.day_off, p_sType
    FROM employees e
    CROSS JOIN (SELECT p_dStart+LEVEL AS DAY_OFF
                FROM DUAL
                CONNECT BY LEVEL <= p_dEnd - p_dStart) do
    WHERE e.employee_id = p_nEmployeeID
    AND SUBSTR(e.workdays, TO_CHAR(do.day_off, 'D'), 1) = 'Y'
    AND NOT EXISTS (SELECT 'X' FROM holidays h WHERE h.holiday_date = do.day_off);
END;
/

【讨论】:

  • 谢谢,我会试一试
  • @Beefstu:很抱歉造成误解。硬编码和匿名块只是我懒惰并且不想在我的数据库中创建对象。它始终是一个程序。
  • 这一次只能用于 1 个employee_id 吗?在我原来的帖子中,我试图让所有员工都参与进来。 work_days 标志 Y/N 确定是否为那一天添加了一行。怎么能叫?就像我与 EXEC 的原始帖子一样
  • @Beefstu 是的,这只会做 1。如果您想要全部删除员工 ID 的参数并注释掉 WHERE 子句的那部分
  • 我只想拥有一个可以遍历日期的地方。可以修改您的示例以调用我的函数 DATE 函数还是效率低下。我是开发新手,对于基本问题感到抱歉
猜你喜欢
  • 2012-09-26
  • 2015-03-20
  • 2019-02-12
  • 1970-01-01
  • 1970-01-01
  • 2023-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多