循环插入日期每日提交日期到日期时间戳ORACLE

时间:2018-02-20 08:59:21

标签: oracle oracle11g

我在oracle中执行查询。我需要插入数据每天提交循环,如下所示:

DECLARE
   start_date      NUMBER;
   end_date        NUMBER;
   business_date   VARCHAR2 (8);
BEGIN
   start_date := TO_NUMBER (TO_CHAR (TO_DATE ('2017-01-01', 'yyyy-MM-dd')));
   end_date := TO_NUMBER (TO_CHAR (TO_DATE ('2018-01-01', 'yyyy-MM-dd')));
   FOR cur_r IN start_date .. end_date
   LOOP
      INSERT INTO file_backup
         SELECT *
           FROM file_core
          WHERE TO_NUMBER (TO_CHAR (TO_DATE (datecreated, 'yyyy-MM-dd')))>=start_date+cur_r
            AND TO_NUMBER (TO_CHAR (TO_DATE (datecreated, 'yyyy-MM-dd')))<=end_date;
            COMMIT;
   END LOOP;
END;

我知道错误这个脚本..请帮帮我..顺便说一下我在oracle的新手抱歉..

5 个答案:

答案 0 :(得分:3)

您不需要任何循环,您应该跳过所有这些TO_CHARTO_NUMBERTO_DATE次转化。试试这个:

INSERT INTO file_backup
SELECT *
FROM file_core
WHERE datecreated BETWEEN DATE '2017-01-01' AND DATE '2018-01-01';

或许datecreated的时间值与00:00:00不同,在这种情况下您应该运行

INSERT INTO file_backup
SELECT *
FROM file_core
WHERE TRUNC(datecreated) BETWEEN DATE '2017-01-01' AND DATE '2018-01-01';

或者datecreated是VARCHAR2数据类型而不是DATE运行

INSERT INTO file_backup
SELECT *
FROM file_core
WHERE TO_DATE(datecreated, 'YYYY-MM-DD') BETWEEN DATE '2017-01-01' AND DATE '2018-01-01';

答案 1 :(得分:3)

正如@boneist指出的那样,使用数字进行操作并不会起作用。您应保持数据类型不变,并与相同数据类型的值进行比较。

假设您有合理的需要在循环中执行此操作,可以执行以下操作:

BEGIN
  FOR r IN (
    select date '2017-01-01' + level -1 as this_date
    from dual
    connect by level <= date '2018-01-01' - date '2017-01-01'
  )
  LOOP
    INSERT INTO file_backup
      SELECT *
        FROM file_core
       WHERE datecreated >= r.this_date
         AND datecreated < r.this_date + 1;
    COMMIT;
  END LOOP;
END;
/

或者,如果数据类型实际上是时间戳而不是评论中建议的日期,则类似:

BEGIN
  FOR r IN (
    select timestamp '2017-01-01 00:00:00'
      + (level -1) * interval '1' day as this_timestamp
    from dual
    connect by level <= extract(day from timestamp '2018-01-01 00:00:00'
      - timestamp '2017-01-01 00:00:00')
  )
  LOOP
    INSERT INTO file_backup
      SELECT *
        FROM file_core
       WHERE datecreated >= r.this_timestamp
         AND datecreated < r.this_timestamp + interval '1' day;
    COMMIT;
  END LOOP;
END;
/

...虽然您可能希望处理连接查询的条件,例如

  FOR r IN (
    select timestamp '2017-01-01 00:00:00'
      + numtodsinterval(level -1, 'DAY') as this_timestamp
    from dual
    connect by timestamp '2017-01-01 00:00:00'
      + numtodsinterval(level -1, 'DAY') < timestamp '2018-01-01 00:00:00'
  )
  LOOP
  ...

或@bone在评论中建议,使用更简单的循环:

BEGIN
  FOR num_days in 0..(date '2018-01-01' - date '2017-01-01' - 1)
  LOOP
    INSERT INTO file_backup
      SELECT *
        FROM file_core
       WHERE datecreated >= timestamp '2017-01-01 00:00:00'
               + numtodsinterval(num_days, 'DAY')
         AND datecreated < timestamp '2017-01-01 00:00:00'
               + numtodsinterval(num_days + 1, 'DAY');
    COMMIT;
  END LOOP;
END;
/

这种方法的主要问题是可重启性。如果在循环过程中出现错误,则无法重新运行它,因为您要插入重复项。

多个插入和提交的效率也低于单个插入,甚至多个插入和单个提交。如果您没有足够的撤消空间来允许单个事务执行您需要的所有工作,那么您应该修复数据库配置以允许它,而不是解决它并可能危及数据完整性。

  

我需要备份此表。并且只在新表中插入2个月

听起来你需要按月对表进行分区,并使用分区交换来将旧月从现场转移到备份表。分区成本更高,但如果您拥有这些数据量,则可能是合理的。

如果没有,您可以考虑将当前表重命名为备份,重新创建原始表,然后只复制两个月的时间。值得您关注的数据。但这是一次性的事情,你仍然存在从主表和备份中老化记录的持续问题。它有自己的依赖关系,约束等问题。

答案 2 :(得分:2)

假设您的datecreated列的数据类型为DATE,并且您只需要表的一行副本,那么您不需要PL / SQL:

INSERT INTO file_backup
  SELECT *
  FROM file_core
  WHERE datecreated BETWEEN DATE '2017-01-01' AND DATE '2018-01-01';
COMMIT;

答案 3 :(得分:1)

您可以使用DATE字面设置start_date和end_date,并使用loop这样的内容。

DECLARE
   start_date      NUMBER;
   end_date        NUMBER;
BEGIN
   start_date := DATE '2017-01-01';
   end_date   := DATE '2018-01-01';

   FOR cur_r IN 0 .. (end_date - start_date)
   LOOP
      INSERT INTO file_backup
         SELECT *
           FROM file_core
          WHERE  TRUNC (datecreated) = start_date + cur_r;

   COMMIT;                              
   END LOOP;

 END;

答案 4 :(得分:0)

为什么不使用简单的INSERT(例如

)来执行此操作
INSERT INTO file_backup
   SELECT *
     FROM file_core
    WHERE datecreated BETWEEN DATE '2017-01-01' AND DATE '2018-01-01';

如果您只是练习PL / SQL和循环,那么,从LOOP中删除COMMIT。 START和END_DATE都应该&#34;转换&#34;使用适当的格式掩码(即yyyymmdd)的数字。 FOR循环索引应该从1到END到START_DATE之间的差异。

[编辑,阅读MT0评论后]

[编辑#2,在阅读了更多评论后]

呸,我的代码是垃圾,应该考虑我在做什么。基本上,如果我打算写得恰到好处,它看起来就像是@Kaushik Nayak,并且两次这样做真的没有意义。