Como faço o spool para um arquivo formatado em CSV usando o SQLPLUS?

143

Quero extrair algumas consultas para um formato de saída CSV. Infelizmente, não posso usar nenhum cliente SQL sofisticado ou qualquer idioma para fazer isso. Eu devo usar o SQLPLUS.

Como eu faço isso?

Daniel C. Sobral
fonte
Por favor, marque como correta a resposta dada pelo @BobC. Falta o comando spool para imprimir o arquivo, mas é a solução mais simples para exportar dados no formato csv.
rlar 17/04

Respostas:

28

Se você estiver usando o 12.2, pode simplesmente dizer

set markup csv on
spool myfile.csv
BobC
fonte
Alguém sabe como desativar o eco, o óbvio "definir eco desativado" não parece funcionar com isso?
Quaternion
Supondo que isso seja porque você está executando um script e gravando em um arquivo, você deve apenas "desativar o termout"
BobC:
155

Você também pode usar o seguinte, embora ele introduza espaços entre os campos.

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;

A saída será como:

    TABLE_PRIVILEGE_MAP           ,SYSTEM                        
    SYSTEM_PRIVILEGE_MAP          ,SYSTEM                        
    STMT_AUDIT_OPTION_MAP         ,SYSTEM                        
    DUAL                          ,SYSTEM 
...

Isso seria muito menos entediante do que digitar todos os campos e concatená-los com vírgulas. Você pode seguir com um script sed simples para remover o espaço em branco que aparece antes de uma vírgula, se desejar.

Algo como isso pode funcionar ... (minhas habilidades de sed são muito enferrujadas, então isso provavelmente precisará de trabalho)

sed 's/\s+,/,/' myfile.csv 
Gabe
fonte
O "," está ausente na linha colsep. Além disso, o headsep off e o tamanho de linha X provavelmente serão úteis. Edite a resposta e eu aceito.
1813 Daniel C. Sobral
5
O comando sed é: cat myfile.csv | sed -e 's / [\ t] * | / | / g; s / | [] * / | / g '> meuarquivo.csv. De qualquer forma, a Oracle é realmente péssima.
Stan
2
E para obter um cabeçalho com os nomes das colunas usar set pagesize 1000, em vez de 0. Na minha comentário anterior, você não pode redirecionar para o mesmo arquivo: cat myfile.csv | sed -e 's/[ \t]*|/|/g ; s/|[ ]*/|/g' > my_other_file.csv.
Stan
1
Eu filtrava os espaços em branco e os traços usados ​​para sublinhar grepe trassim grep -v -- ----- myfile.csv | tr -d [:blank:] > myfile.csv.
ixe013
1
@slayernoah o comando spool pode usar o caminho do diretório e o nome do arquivo, para que você possa especificar exatamente onde o arquivo de saída será colocado. Caso contrário, isso dependeria do local em que você está executando o script.
Gabe
35

Eu uso esse comando para scripts que extrai dados para tabelas dimensionais (DW). Então, eu uso a seguinte sintaxe:

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

E funciona. Eu não uso sed para formatar o arquivo de saída.

Hallison Batista
fonte
24

Vejo um problema semelhante ...

Preciso colocar em spool o arquivo CSV do SQLPLUS, mas a saída possui 250 colunas.

O que fiz para evitar a irritante formatação de saída 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

o problema é que você perderá os nomes dos cabeçalhos das colunas ...

você pode adicionar isto:

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

Eu sei que é meio hardcore, mas funciona para mim ...

Karlos
fonte
também precisamos ||de subconsulta ?, acho que não é necessário para as subconsultas. mas sim, é necessário para a seleção primária.
Davidb
Para que serve o exterior extra select x? Isso deve funcionar sem ele. @ Davididb, você está certo de que a concatenação não é necessária na subconsulta interna primária, mas com o alias de todas as colunas como col1, col2 ... etc. é necessário lá.
Amit Naidu
18

Com versões mais recentes das ferramentas do cliente, há várias opções para formatar a saída da consulta. O restante é colocar em spool em um arquivo ou salvar a saída como um arquivo, dependendo da ferramenta do cliente. Aqui estão algumas das maneiras:

  • SQL * Plus

Usando os comandos SQL * Plus, você pode formatar para obter a saída desejada. Use SPOOL para colocar a saída em spool em um arquivo.

Por exemplo,

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>
  • Versão do desenvolvedor SQL anterior 4.1

Como alternativa, você pode usar a nova dica no SQL Developer ./*csv*/

/*csv*/

Por exemplo, no meu SQL Developer Versão 3.2.20.10 :

insira a descrição da imagem aqui

Agora você pode salvar a saída em um arquivo.

  • SQL Developer Versão 4.1

Novo no SQL Developer versão 4.1, use o seguinte como o comando sqlplus e execute como script. Não há necessidade da dica na consulta.

SET SQLFORMAT csv

Agora você pode salvar a saída em um arquivo.

Lalit Kumar B
fonte
12

Eu sei que este é um thread antigo, no entanto, notei que ninguém mencionou a opção de sublinhado, que pode remover os sublinhados sob os títulos das colunas.

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;
Doc
fonte
Boa captura na opção sublinhada, precisava dessa.
Knockando
É bom se você quiser um csv com uma linha superior que contenha o título / títulos de cada coluna. Isso ajudaria qualquer um que pode querer ver o arquivo CSV, e descobrir o que eles estão olhando, etc ...
Doc
10

É bruto, mas:

set pagesize 0 linesize 500 trimspool on feedback off echo off

select '"' || empno || '","' || ename || '","' || deptno || '"' as text
from emp

spool emp.csv
/
spool off
Tony Andrews
fonte
7

Você pode formatar explicitamente a consulta para produzir uma sequência delimitada com algo parecido com:

select '"'||foo||'","'||bar||'"'
  from tab

E configure as opções de saída conforme apropriado. Como opção, a variável COLSEP no SQLPlus permitirá produzir arquivos delimitados sem a necessidade de gerar explicitamente uma sequência com os campos concatenados juntos. No entanto, você precisará colocar aspas nas seqüências de caracteres em qualquer coluna que possa conter caracteres de vírgula incorporados.

ConcernedOfTunbridgeWells
fonte
4

prefira usar "set colsep" no prompt do sqlplus em vez de editar o nome da coluna, um por um. Use sed para editar o arquivo de saída.

set colsep '","'     -- separate columns with a comma
sed 's/^/"/;s/$/"/;s/\s *"/"/g;s/"\s */"/g' $outfile > $outfile.csv
CC
fonte
3

Certa vez, escrevi um pequeno script SQL * Plus que usa dbms_sqle dbms_outputcria um csv (na verdade um ssv). Você pode encontrá-lo no meu repositório githup .

René Nyffenegger
fonte
2

Você deve estar ciente de que os valores dos campos podem conter vírgulas e caracteres de cotação, portanto, algumas das respostas sugeridas não funcionariam, pois o arquivo de saída CSV não estaria correto. Para substituir caracteres de aspas em um campo e substituí-los pelo caractere de aspas duplas, você pode usar a função REPLACE fornecida pelo oracle, para alterar uma aspas simples para aspas duplas.

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

Ou, se você desejar o caractere de aspas simples para os campos:

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
Rob Heusdens
fonte
O trim()é desnecessário.
Amit Naidu
1

Use vi ou vim para escrever o sql, use colsep com um controle-A (no vi e vim preceda o ctrl-A com um ctrl-v). Certifique-se de definir o tamanho da linha e o tamanho da página como algo racional e ative o trimspool e o trimout.

coloque em um arquivo em spool. Então...

sed -e 's/,/;/g' -e 's/ *{ctrl-a} */,/g'  {spooled file}  > output.csv

Essa coisa sed pode ser transformada em um script. O "*" antes e depois do ctrl-A apaga todos os espaços inúteis. Não é ótimo que eles se preocuparam em habilitar a saída html do sqlplus, mas NÃO o csv nativo ?????

Eu faço dessa maneira porque lida com vírgulas nos dados. Eu os transforma em ponto e vírgula.

Charles Stepp
fonte
3
Isso falha no teste "Preciso usar o SQLPlus".
Daniel C. Sobral
0

Há um problema ao usar o sqlplus para criar arquivos csv. Se você quiser os cabeçalhos das colunas apenas uma vez na saída e houver milhares ou milhões de linhas, não poderá definir o tamanho da página suficientemente grande para não repetir. A solução é começar com tamanho da página = 50 e analisar os cabeçalhos e emitir o select novamente com tamanho da página = 0 para obter os dados. Veja o script bash abaixo:

#!/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
}
Larry R. Irwin
fonte
0

Eu escrevi esse script puramente SQLPlus para despejar tabelas no CSV em 1994.

Conforme observado nos comentários do script, alguém na Oracle colocou meu script em uma nota de suporte Oracle, mas sem atribuição.

https://github.com/jkstill/oracle-script-lib/blob/master/sql/dump.sql

O script também cria um arquivo de controle e um arquivo de parâmetro para SQL * LOADER

Jared Still
fonte
-1
spool D:\test.txt

    select * from emp
    
    spool off
Satheeshkumar P
fonte
-3

Você pode usar a dica csv. Veja o seguinte exemplo:

select /*csv*/ table_name, tablespace_name
from all_tables
where owner = 'SYS'
and tablespace_name is not null;
Adilson Silva
fonte