SQL:如何将 Oracle table 中的 100,000 条记录分成 5 个块?
SQL: How would you split a 100,000 records from a Oracle table into 5 chunks?
我正在尝试将前 100,000 条记录从具有 100 万条以上记录的 table 拆分为 5(五)个 20,000 条记录块以放入文件中?
也许一些 SQL 会为 20,000 条记录的每 5 个块获取最小和最大 rowid 或主 ID,因此我可以将最小值和最大值放入变量并将其传递到 SQL 并使用SQL.
的 where 子句中的 BETWEEN
这可以做到吗?
我在 Oracle 11g 数据库上。
提前致谢。
如果您只想将值 1-5 分配给大小基本相等的组,请使用 ntile()
:
select t.*, ntile(5) over (order by NULL) as num
from (select t.*
from t
where rownum <= 100000
) t;
如果要插入到 5 个不同的表中,则使用 insert all
:
insert all
when num = 1 then into t1
when num = 2 then into t2
when num = 3 then into t3
when num = 4 then into t4
when num = 5 then into t5
select t.*, ntile(5) over (order by NULL) as num
from (select t.*
from t
where rownum <= 100000
) t;
非常感谢 Gordon Linoff 为我提供了代码入门。
只是关于如何获取 5 个块的最小值和最大值的更新。
select num, min(cre_surr_id), max(cre_surr_id)
from
(select p.cre_surr_id, ntile(5) over (order by NULL) as num
from (select p.*
from productions p
where rownum <= 100000
) p )
group by num
您甚至可以尝试简单聚合:
create table test_chunk(val) as
(
select floor(dbms_random.value(1, level * 10)) from dual
connect by level <= 100
)
select min(val), max(val), floor((num+1)/2)
from (select rownum as num, val from test_chunk)
group by floor((num+1)/2)
对另一个公平的问题投反对票有点苛刻。
无论如何,NTILE 对我来说是新手,所以如果不是你的问题,我不会发现它。
我这样做的方式,老派的方式,是 MOD rownum 来获取组号,例如
select t.*, mod(rn,5) as num
from (select t.*, rownnum rn
from t
) t;
这解决了 SQL 部分,或者更确切地说,如何将行分组为相等的块,但这只是你的问题的一半。下半部分是如何将它们写入 5 个单独的文件。
您可以有 5 个单独的查询,每个查询假脱机到一个单独的文件,例如:
spool f1.dat
select t.*
from (select t.*, rownnum rn
from t
) t
where mod(t.rn,5) = 0;
spool off
spool f2.dat
select t.*
from (select t.*, rownnum rn
from t
) t
where mod(t.rn,5) = 1;
spool off
等等
或者,使用 UTL_FILE。您可以通过单个查询尝试一些巧妙的事情,并拥有一个 UTL_FILE 类型的数组,其中数组索引与 MOD(rn,5) 匹配,那么您就不需要像 "IF rn = 0 THEN UTL_FILE.WRITELN(f0, ..." 这样的逻辑。
所以,类似(未经测试,只是粗略的指导形式,我自己从未尝试过):
DECLARE
TYPE fname IS VARRAY(5) OF VARCHAR2(100);
TYPE fh IS VARRAY(5) OF UTL_FILE.FILE_TYPE;
CURSOR c1 IS
select t.*, mod(rn,5) as num
from (select t.*, rownnum rn
from t
) t;
idx INTEGER;
BEGIN
FOR idx IN 1..5 LOOP
fname(idx) := 'data_' || idx || '.dat';
fh(idx) := UTL_FILE.'THE_DIR', fname(idx), 'w');
END LOOP;
FOR r1 IN c1 LOOP
UTL_FILE.PUT_LINE ( fh(r1.num+1), r1.{column value from C1} );
END LOOP;
FOR idx IN 1..5 LOOP
UTL_FILE.FCLOSE (fh(idx));
END LOOP;
END;
我正在尝试将前 100,000 条记录从具有 100 万条以上记录的 table 拆分为 5(五)个 20,000 条记录块以放入文件中? 也许一些 SQL 会为 20,000 条记录的每 5 个块获取最小和最大 rowid 或主 ID,因此我可以将最小值和最大值放入变量并将其传递到 SQL 并使用SQL.
的 where 子句中的 BETWEEN这可以做到吗?
我在 Oracle 11g 数据库上。
提前致谢。
如果您只想将值 1-5 分配给大小基本相等的组,请使用 ntile()
:
select t.*, ntile(5) over (order by NULL) as num
from (select t.*
from t
where rownum <= 100000
) t;
如果要插入到 5 个不同的表中,则使用 insert all
:
insert all
when num = 1 then into t1
when num = 2 then into t2
when num = 3 then into t3
when num = 4 then into t4
when num = 5 then into t5
select t.*, ntile(5) over (order by NULL) as num
from (select t.*
from t
where rownum <= 100000
) t;
非常感谢 Gordon Linoff 为我提供了代码入门。
只是关于如何获取 5 个块的最小值和最大值的更新。
select num, min(cre_surr_id), max(cre_surr_id)
from
(select p.cre_surr_id, ntile(5) over (order by NULL) as num
from (select p.*
from productions p
where rownum <= 100000
) p )
group by num
您甚至可以尝试简单聚合:
create table test_chunk(val) as
(
select floor(dbms_random.value(1, level * 10)) from dual
connect by level <= 100
)
select min(val), max(val), floor((num+1)/2)
from (select rownum as num, val from test_chunk)
group by floor((num+1)/2)
对另一个公平的问题投反对票有点苛刻。
无论如何,NTILE 对我来说是新手,所以如果不是你的问题,我不会发现它。
我这样做的方式,老派的方式,是 MOD rownum 来获取组号,例如
select t.*, mod(rn,5) as num
from (select t.*, rownnum rn
from t
) t;
这解决了 SQL 部分,或者更确切地说,如何将行分组为相等的块,但这只是你的问题的一半。下半部分是如何将它们写入 5 个单独的文件。
您可以有 5 个单独的查询,每个查询假脱机到一个单独的文件,例如:
spool f1.dat
select t.*
from (select t.*, rownnum rn
from t
) t
where mod(t.rn,5) = 0;
spool off
spool f2.dat
select t.*
from (select t.*, rownnum rn
from t
) t
where mod(t.rn,5) = 1;
spool off
等等
或者,使用 UTL_FILE。您可以通过单个查询尝试一些巧妙的事情,并拥有一个 UTL_FILE 类型的数组,其中数组索引与 MOD(rn,5) 匹配,那么您就不需要像 "IF rn = 0 THEN UTL_FILE.WRITELN(f0, ..." 这样的逻辑。
所以,类似(未经测试,只是粗略的指导形式,我自己从未尝试过):
DECLARE
TYPE fname IS VARRAY(5) OF VARCHAR2(100);
TYPE fh IS VARRAY(5) OF UTL_FILE.FILE_TYPE;
CURSOR c1 IS
select t.*, mod(rn,5) as num
from (select t.*, rownnum rn
from t
) t;
idx INTEGER;
BEGIN
FOR idx IN 1..5 LOOP
fname(idx) := 'data_' || idx || '.dat';
fh(idx) := UTL_FILE.'THE_DIR', fname(idx), 'w');
END LOOP;
FOR r1 IN c1 LOOP
UTL_FILE.PUT_LINE ( fh(r1.num+1), r1.{column value from C1} );
END LOOP;
FOR idx IN 1..5 LOOP
UTL_FILE.FCLOSE (fh(idx));
END LOOP;
END;