【问题标题】:How do I spool to a CSV formatted file using SQLPLUS?如何使用 SQLPLUS 假脱机到 CSV 格式的文件?
【发布时间】:2010-10-13 04:33:27
【问题描述】:

我想将一些查询提取为 CSV 输出格式。不幸的是,我不能使用任何花哨的 SQL 客户端或任何语言来做到这一点。我必须使用 SQLPLUS。

我该怎么做?

【问题讨论】:

    标签: sql oracle csv 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
    • 我过滤掉了greptr下划线的空格和破折号,就像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.1

      SQL 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_sqldbms_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;
                      

                      【讨论】:

                        猜你喜欢
                        • 2013-08-01
                        • 2018-05-22
                        • 1970-01-01
                        • 2017-02-14
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多