如何使用 SQLPLUS 假脱机到 CSV 格式的文件?
Posted
技术标签:
【中文标题】如何使用 SQLPLUS 假脱机到 CSV 格式的文件?【英文标题】:How do I spool to a CSV formatted file using SQLPLUS? 【发布时间】:2010-10-13 04:33:27 【问题描述】:我想将一些查询提取为 CSV 输出格式。不幸的是,我不能使用任何花哨的 SQL 客户端或任何语言来做到这一点。我必须使用 SQLPLUS。
我该怎么做?
【问题讨论】:
【参考方案1】:您也可以使用以下内容,尽管它确实在字段之间引入了空格。
set colsep , -- separate columns with a comma
set pagesize 0 -- No header rows
set trimspool on -- remove trailing blanks
set headsep off -- this may or may not be useful...depends on your headings.
set linesize X -- X should be the sum of the column widths
set numw X -- X should be the length you want for numbers (avoid scientific notation on IDs)
spool myfile.csv
select table_name, tablespace_name
from all_tables
where owner = 'SYS'
and tablespace_name is not null;
输出如下:
TABLE_PRIVILEGE_MAP ,SYSTEM
SYSTEM_PRIVILEGE_MAP ,SYSTEM
STMT_AUDIT_OPTION_MAP ,SYSTEM
DUAL ,SYSTEM
...
这比输入所有字段并用逗号连接起来要简单得多。如果需要,您可以使用一个简单的 sed 脚本来删除逗号前出现的空格。
这样的事情可能会奏效......(我的 sed 技能非常生疏,所以这可能需要工作)
sed 's/\s+,/,/' myfile.csv
【讨论】:
在 colsep 行中缺少“,”。 Headsep off 和 linesize X 也可能有用。编辑答案,我会接受。 sed 命令是:cat myfile.csv | sed -e 's/[ \t]*|/|/g ; s/|[ ]*/|/g' > myfile.csv。无论如何,甲骨文真的很烂。 要获得带有列名的标题,请使用set pagesize 1000
而不是 0。在我之前的评论中,您不能重定向到同一个文件:cat myfile.csv | sed -e 's/[ \t]*|/|/g ; s/|[ ]*/|/g' > my_other_file.csv
。
我过滤掉了grep
和tr
下划线的空格和破折号,就像grep -v -- ----- myfile.csv | tr -d [:blank:] > myfile.csv
一样。
@slayernoah spool 命令可以采用目录路径和文件名,以便您可以准确指定输出文件的放置位置。否则,它将取决于您执行脚本的位置。【参考方案2】:
如果你使用的是12.2,你可以简单地说
set markup csv on
spool myfile.csv
【讨论】:
有谁知道如何关闭回声,明显的“设置回声关闭”似乎不适用于此? 假设这是因为您正在执行脚本并写入文件,您应该“设置 termout 关闭” 如果还想设置分隔符:SET MARKUP CSV ON DELIMITER |
【参考方案3】:
我将此命令用于为维度表 (DW) 提取数据的脚本。所以,我使用以下语法:
set colsep '|'
set echo off
set feedback off
set linesize 1000
set pagesize 0
set sqlprompt ''
set trimspool on
set headsep off
spool output.dat
select '|', <table>.*, '|'
from <table>
where <conditions>
spool off
并且有效。我不使用 sed 格式化输出文件。
【讨论】:
【参考方案4】:我看到了类似的问题...
我需要从 SQLPLUS 假脱机 CSV 文件,但输出有 250 列。
我做了什么来避免烦人的 SQLPLUS 输出格式:
set linesize 9999
set pagesize 50000
spool myfile.csv
select x
from
(
select col1||';'||col2||';'||col3||';'||col4||';'||col5||';'||col6||';'||col7||';'||col8||';'||col9||';'||col10||';'||col11||';'||col12||';'||col13||';'||col14||';'||col15||';'||col16||';'||col17||';'||col18||';'||col19||';'||col20||';'||col21||';'||col22||';'||col23||';'||col24||';'||col25||';'||col26||';'||col27||';'||col28||';'||col29||';'||col30 as x
from (
... here is the "core" select
)
);
spool off
问题是您将丢失列标题名称...
你可以添加这个:
set heading off
spool myfile.csv
select col1_name||';'||col2_name||';'||col3_name||';'||col4_name||';'||col5_name||';'||col6_name||';'||col7_name||';'||col8_name||';'||col9_name||';'||col10_name||';'||col11_name||';'||col12_name||';'||col13_name||';'||col14_name||';'||col15_name||';'||col16_name||';'||col17_name||';'||col18_name||';'||col19_name||';'||col20_name||';'||col21_name||';'||col22_name||';'||col23_name||';'||col24_name||';'||col25_name||';'||col26_name||';'||col27_name||';'||col28_name||';'||col29_name||';'||col30_name from dual;
select x
from
(
select col1||';'||col2||';'||col3||';'||col4||';'||col5||';'||col6||';'||col7||';'||col8||';'||col9||';'||col10||';'||col11||';'||col12||';'||col13||';'||col14||';'||col15||';'||col16||';'||col17||';'||col18||';'||col19||';'||col20||';'||col21||';'||col22||';'||col23||';'||col24||';'||col25||';'||col26||';'||col27||';'||col28||';'||col29||';'||col30 as x
from (
... here is the "core" select
)
);
spool off
我知道这有点硬核,但它对我有用...
【讨论】:
子查询是否也需要||
?我认为子查询不需要。但是是的,它是主要选择所必需的。
额外的外部select x
是什么?没有它应该可以工作。 @davidb,您是对的,主内部子查询中不需要连接,而是将所有列别名为 col1,col2 ......等。那里是必需的。【参考方案5】:
对于较新版本的客户端工具,有多种选项可用于格式化查询输出。剩下的就是根据客户端工具将其假脱机到文件或将输出另存为文件。以下是几种方法:
SQL*Plus使用 SQL*Plus 命令,您可以格式化以获得所需的输出。使用 SPOOL 将输出假脱机到文件中。
例如,
SQL> SET colsep ,
SQL> SET pagesize 20
SQL> SET trimspool ON
SQL> SET linesize 200
SQL> SELECT * FROM scott.emp;
EMPNO,ENAME ,JOB , MGR,HIREDATE , SAL, COMM, DEPTNO
----------,----------,---------,----------,---------,----------,----------,----------
7369,SMITH ,CLERK , 7902,17-DEC-80, 800, , 20
7499,ALLEN ,SALESMAN , 7698,20-FEB-81, 1600, 300, 30
7521,WARD ,SALESMAN , 7698,22-FEB-81, 1250, 500, 30
7566,JONES ,MANAGER , 7839,02-APR-81, 2975, , 20
7654,MARTIN ,SALESMAN , 7698,28-SEP-81, 1250, 1400, 30
7698,BLAKE ,MANAGER , 7839,01-MAY-81, 2850, , 30
7782,CLARK ,MANAGER , 7839,09-JUN-81, 2450, , 10
7788,SCOTT ,ANALYST , 7566,09-DEC-82, 3000, , 20
7839,KING ,PRESIDENT, ,17-NOV-81, 5000, , 10
7844,TURNER ,SALESMAN , 7698,08-SEP-81, 1500, , 30
7876,ADAMS ,CLERK , 7788,12-JAN-83, 1100, , 20
7900,JAMES ,CLERK , 7698,03-DEC-81, 950, , 30
7902,FORD ,ANALYST , 7566,03-DEC-81, 3000, , 20
7934,MILLER ,CLERK , 7782,23-JAN-82, 1300, , 10
14 rows selected.
SQL>
SQL Developer 4.1 之前的版本
或者,您可以在 SQL Developer 中使用新的 /*csv*/
hint。
/*csv*/
例如,在我的 SQL Developer 版本 3.2.20.10 中:
现在您可以将输出保存到文件中。
SQL Developer 版本 4.1SQL Developer 版本 4.1 中的新功能,像 sqlplus 命令一样使用以下命令并作为脚本运行。查询中不需要提示。
SET SQLFORMAT csv
现在您可以将输出保存到文件中。
【讨论】:
【参考方案6】:我知道这是一个旧线程,但是我注意到没有人提到下划线选项,它可以删除列标题下的下划线。
set pagesize 50000--50k is the max as of 12c
set linesize 10000
set trimspool on --remove trailing blankspaces
set underline off --remove the dashes/underlines under the col headers
set colsep ~
select * from DW_TMC_PROJECT_VW;
【讨论】:
下划线选项不错,需要那个。 如果您想要一个顶行包含每列标题/标题的 csv,那就太好了。这将有助于任何可能想要查看 csv 文件并弄清楚他们在看什么的人,等等......【参考方案7】:这很粗糙,但是:
set pagesize 0 linesize 500 trimspool on feedback off echo off
select '"' || empno || '","' || ename || '","' || deptno || '"' as text
from emp
spool emp.csv
/
spool off
【讨论】:
【参考方案8】:您可以显式格式化查询以生成带有以下内容的分隔字符串:
select '"'||foo||'","'||bar||'"'
from tab
并根据需要设置输出选项。作为一个选项,SQLPlus 上的 COLSEP 变量将允许您生成分隔文件,而无需显式生成将字段连接在一起的字符串。但是,您必须在可能包含嵌入式逗号字符的任何列上为字符串加上引号。
【讨论】:
【参考方案9】:宁愿在 sqlplus 提示符下使用“set colsep”,而不是一一编辑 col 名称。使用 sed 编辑输出文件。
set colsep '","' -- separate columns with a comma
sed 's/^/"/;s/$/"/;s/\s *"/"/g;s/"\s */"/g' $outfile > $outfile.csv
【讨论】:
【参考方案10】:我曾经写过一个小的 SQL*Plus 脚本,它使用 dbms_sql
和 dbms_output
创建一个 csv(实际上是一个 ssv)。你可以找到它on my githup repository。
【讨论】:
【参考方案11】:您应该知道,字段的值可能包含逗号和引号字符,因此某些建议的答案将不起作用,因为 CSV 输出文件不正确。 要将字段中的引号字符替换为双引号字符,可以使用oracle提供的REPLACE函数,将单引号改为双引号。
set echo off
set heading off
set feedback off
set linesize 1024 -- or some other value, big enough
set pagesize 50000
set verify off
set trimspool on
spool output.csv
select trim(
'"' || replace(col1, '"', '""') ||
'","' || replace(col2, '"', '""') ||
'","' || replace(coln, '"', '""') || '"' ) -- etc. for all the columns
from yourtable
/
spool off
或者,如果您想要字段的单引号字符:
set echo off
set heading off
set feedback off
set linesize 1024 -- or some other value, big enough
set pagesize 50000
set verify off
set trimspool on
spool output.csv
select trim(
'"' || replace(col1, '''', '''''') ||
'","' || replace(col2, '''', '''''') ||
'","' || replace(coln, '''', '''''') || '"' ) -- etc. for all the columns
from yourtable
/
spool off
【讨论】:
trim()
是不必要的。
对于我们这些仍然停留在过去的 11.2.0.4 的人,不要忘记文件底部的“设置时间关闭”和“设置反馈关闭”。【参考方案12】:
使用 vi 或 vim 编写 sql,使用 colsep 和 control-A(在 vi 和 vim 中,在 ctrl-A 之前使用 ctrl-v)。确保将 linesize 和 pagesize 设置为合理的值并打开 trimspool 和 trimout。
把它放到一个文件中。 那么……
sed -e 's/,/;/g' -e 's/ *ctrl-a */,/g' spooled file > output.csv
那个 sed 的东西可以变成一个脚本。 ctrl-A 前后的“*”挤出所有无用的空格。他们费心启用 sqlplus 的 html 输出而不是原生 csv,这不是很好吗????
我这样做是因为它处理数据中的逗号。我把它们变成分号。
【讨论】:
这未通过“我必须使用 SQLPlus”测试。【参考方案13】:使用 sqlplus 创建 csv 文件时出现问题。如果您只希望列标题在输出中出现一次并且有数千或数百万行,则不能将页面大小设置得足够大而不会重复。 解决方案是从 pagesize = 50 开始并解析出标题,然后再次发出选择 pagesize = 0 以获取数据。请参阅下面的 bash 脚本:
#!/bin/bash
FOLDER="csvdata_mydb"
CONN="192.168.100.11:1521/mydb0023.world"
CNT=0376
ORD="0376"
TABLE="MY_ATTACHMENTS"
sqlplus -L logn/pswd@//$CONN<<EOF >/dev/null
set pagesize 50;
set verify off;
set feedback off;
set long 99999;
set linesize 32767;
set trimspool on;
col object_ddl format A32000;
set colsep ,;
set underline off;
set headsep off;
spool $ORD$TABLE.tmp;
select * from tblspc.$TABLE where rownum < 2;
EOF
LINES=`wc -l $ORD$TABLE.tmp | cut -f1 -d" "`
[ $LINES -le 3 ] &&
echo "No Data Found in $TABLE."
[ $LINES -gt 3 ] &&
cat $ORD$TABLE.tmp | sed -e 's/ * / /g' -e 's/^ //' -e 's/ ,/,/g' -e 's/, /,/g' | tail -n +3 | head -n 1 > ./$ORD$TABLE.headers
sqlplus -L logn/pswd@//$CONN<<EOF >/dev/null
set pagesize 0;
set verify off;
set feedback off;
set long 99999;
set linesize 32767;
set trimspool on;
col object_ddl format A32000;
set colsep ,;
set underline off;
set headsep off;
spool $ORD$TABLE.tmp;
select * from tblspc.$TABLE;
EOF
LINES=`wc -l $ORD$TABLE.tmp | cut -f1 -d" "`
[ $LINES -le 3 ] &&
echo "No Data Found in $TABLE."
[ $LINES -gt 3 ] &&
cat $ORD$TABLE.headers > $FOLDER/$ORD$TABLE.csv
cat $ORD$TABLE.tmp | sed -e 's/ * / /g' -e 's/^ //' -e 's/ ,/,/g' -e 's/, /,/g' | tail -n +2 | head -n -1 >> $FOLDER/$ORD$TABLE.csv
【讨论】:
【参考方案14】:我在 1994 年编写了这个纯粹的 SQLPlus 脚本来将表转储到 CSV。
如脚本 cmets 中所述,Oracle 有人将我的脚本放在 Oracle 支持说明中,但未注明出处。
https://github.com/jkstill/oracle-script-lib/blob/master/sql/dump.sql
该脚本还为 SQL*LOADER 构建了一个控制文件和一个参数文件
【讨论】:
【参考方案15】:spool D:\test.txt
select * from emp
spool off
【讨论】:
【参考方案16】:您可以使用 csv 提示。请参阅以下示例:
select /*csv*/ table_name, tablespace_name
from all_tables
where owner = 'SYS'
and tablespace_name is not null;
【讨论】:
以上是关于如何使用 SQLPLUS 假脱机到 CSV 格式的文件?的主要内容,如果未能解决你的问题,请参考以下文章