【问题标题】:Looping spool scripts循环假脱机脚本
【发布时间】:2020-07-22 17:57:03
【问题描述】:

我在 Oracle 数据库中有一个大表,我想将其提取为 CSV,以便将其移动到另一个系统(理想情况下,这两个系统之间应该有直接连接,但如果没有的话,这是下一个最佳解决方案)。

由于表很大,我当时正在提取一个月的数据。所以查询看起来像这样:

set termout off;
set echo off;
set verify off;
spool "C:\output_path\&&1. events.csv";
select /*csv*/ * from my_database.events
where my_date between to_date(&&1,'yyyy-mm-dd') and to_date(&&2,'yyyy-mm-dd');
spool off
set termout on;
set echo on;

然后我从另一个脚本中调用它,如下所示:

@my_script.sql "'2020-01-01'" "'2020-01-31'"

这会将“2020-01-01”和“2020-01-31”分别代替 &&1 和 &&2,并将 1 月份的数据输出到 C:\output_path\'2020-01-01' events.csv

理想情况下,我想把它变成一个循环,这样我就可以有这样的函数(伪python):

def scrape_range_of_months(start_date, end_date)
    date_range = make_date_range(start_date, end_date)
    for date in date_range:
        scrape_month(date, end_of_month(date))

其中 make_date_range() 和 end_of_month() 是独立的函数。

PL/SQL 是一种比 Python 更加神秘的语言,所以虽然我可以找到解决方案的各个部分,但不清楚是否可以像我想要的那样在循环中运行脚本。

【问题讨论】:

  • 1) PL/SQL 并不比任何其他你不流利的语言更神秘。它实际上是建立在 ADA 之上的,它本身是从 Pascal 派生的。 2)如果系统之间没有直接连接,您如何建议在那里获取您的 csv 文件?联邦快递DVD? 3)“大”有多大。 4)如果你在一个循环的脚本中得到这个,产生多个构成“集合”的 csv 文件,与单个 csv 文件相比有什么优势?
  • 必须是SQL*Plus 脚本吗? PL/SQL 允许循环并具有utl_file 包,它可以让您在数据库服务器上创建文件。我不完全确定你为什么首先要分解数据 - 逐月提取数据比一次性提取数据需要更长的时间。再次加载它会做更多的工作。除非表格太大以至于单个文件会超过操作系统允许的最大文件大小或类似的东西......
  • 不清楚是否可以在循环中运行脚本 - PL/SQL 根本无法运行 SQL*Plus 脚本。它是一种在数据库中运行的编程语言。
  • @EdStevens 1) 有限的在线教程(与例如 Python 相比)让新手更难摸索,但显然 ymmv。 2) 从字面上将文件从文件系统拖放到 Amazon S3 中。不幸的是,在这种情况下最好的解决方案(至少在更好的系统上线之前)3)比如 200-500m 记录。 4)随着新数据的到来重复提取。虽然其他表小到可以一次性提取,但这些表太大了。打破它也意味着如果发生崩溃,我不会失去(尽可能多的)进步。

标签: sql oracle plsql oracle-sqldeveloper


【解决方案1】:

@justin Cave 是对的,完整的解决方案是使用 UTL_FILE 直接从 PL/SQL 写入文件。

在这个例子中,我编写了一些 PL/SQL 来生成代码来逐月提取。我将“between”更改为 ">=" 和 "

DECLARE
    l_date    DATE := DATE '2020-01-01';
    c_spool   VARCHAR2( 512 ) := Q'[spool "C:\output_path\YMD.events.csv";
select /*csv*/ * from my_database.events
where my_date >= to_date('YMD','yyyy-mm-dd') and my_date < add_months(to_date('YMD','yyyy-mm-dd'),1);
]';
BEGIN
    WHILE l_date < SYSDATE
    LOOP
        DBMS_OUTPUT.put_line( REPLACE( c_spool
                                     , 'YMD'
                                     , TO_CHAR( l_date, 'yyyy-mm-dd' ) ) );
        l_date   := ADD_MONTHS( l_date, 1 );
    END LOOP;
END;

示例输出:

spool "C:\output_path\2020-02-01.events.csv";
select /*csv*/ * from my_database.events
where my_date >= to_date('2020-02-01','yyyy-mm-dd') and my_date < 
add_months(to_date('2020-02-01','yyyy-mm-dd'),1);

【讨论】:

  • 这很棒,可以满足我的大部分需求。下一步将是另一个脚本(或此脚本中的另一行)来运行它生成的代码)。我猜这就是 UTL_FILE 的用武之地?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-13
  • 2012-01-25
  • 1970-01-01
  • 1970-01-01
  • 2015-07-27
  • 2020-11-30
相关资源
最近更新 更多