Comment puis-je spouler dans un fichier au format CSV à l'aide de SQLPLUS?
143
Je souhaite extraire certaines requêtes dans un format de sortie CSV. Malheureusement, je ne peux utiliser aucun client SQL sophistiqué ni aucun langage pour le faire. Je dois utiliser SQLPLUS.
Veuillez marquer comme correcte la réponse donnée par @BobC. Il manque la commande spool pour imprimer le fichier, mais c'est la solution la plus simple pour exporter des données au format csv.
rlar le
Réponses:
28
Si vous utilisez 12.2, vous pouvez simplement dire
Est-ce que quelqu'un sait comment désactiver l'écho, l'évidente "désactiver l'écho" ne semble pas fonctionner avec cela?
Quaternion
En supposant que cela est dû au fait que vous exécutez un script et que vous écrivez dans un fichier, vous devez simplement "désactiver termout"
BobC
155
Vous pouvez également utiliser ce qui suit, même s'il introduit des espaces entre les champs.
set colsep ,-- separate columns with a commaset pagesize 0-- No header rowsset trimspool on-- remove trailing blanksset headsep off-- this may or may not be useful...depends on your headings.set linesize X -- X should be the sum of the column widthsset 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 isnotnull;
Ce serait beaucoup moins fastidieux que de taper tous les champs et de les concaténer avec des virgules. Vous pouvez poursuivre avec un simple script sed pour supprimer les espaces qui apparaissent avant une virgule, si vous le souhaitez.
Quelque chose comme ça pourrait fonctionner ... (mes compétences sed sont très rouillées, donc cela nécessitera probablement du travail)
Le "," est manquant dans la ligne colsep. De plus, headsep off et linesize X sont susceptibles d'être utiles. Modifiez la réponse et je l'accepterai.
Daniel C. Sobral
5
La commande sed est: cat myfile.csv | sed -e / [\ t] * | / | / g; s / | [] * / | / g '> monfichier.csv. Quoi qu'il en soit, Oracle est vraiment nul.
Stan
2
Et pour un en- tête avec les noms de colonnes utilisent au set pagesize 1000lieu de 0. Dans mon commentaire précédent, vous ne pouvez pas rediriger vers le même fichier: cat myfile.csv | sed -e 's/[ \t]*|/|/g ; s/|[ ]*/|/g' > my_other_file.csv.
Stan
1
J'ai filtré les blancs et les tirets utilisés pour souligner avec grepet trcomme ça grep -v -- ----- myfile.csv | tr -d [:blank:] > myfile.csv.
ixe013
1
@slayernoah la commande spool peut prendre un chemin de répertoire et un nom de fichier, de sorte que vous puissiez spécifier exactement où le fichier de sortie sera placé. Sinon, cela dépendra de l'emplacement où vous exécutez le script.
Gabe
35
J'utilise cette commande pour les scripts qui extrait des données pour les tables dimensionnelles (DW). Donc, j'utilise la syntaxe suivante:
set colsep '|'set echo offset feedback offset linesize 1000set pagesize 0set sqlprompt ''set trimspool onset headsep off
spool output.dat
select'|',<table>.*,'|'from<table>where<conditions>
spool off
Et fonctionne. Je n'utilise pas sed pour formater le fichier de sortie.
J'ai besoin de spouler le fichier CSV à partir de SQLPLUS, mais la sortie a 250 colonnes.
Ce que j'ai fait pour éviter le formatage de la sortie SQLPLUS ennuyeux:
set linesize 9999set 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
le problème est que vous perdrez les noms d'en-tête de colonne ...
vous pouvez ajouter ceci:
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
Je sais que c'est un peu hardcore, mais ça marche pour moi ...
avons-nous besoin ||d'une sous-requête aussi?, je ne pense pas que ce soit nécessaire pour les sous-requêtes. mais oui, il est requis pour la sélection principale.
davidb
À quoi sert le supplément extérieur select x? Cela devrait fonctionner sans cela. @davidb, vous avez raison de dire que la concaténation n'est pas requise dans la sous-requête interne principale, mais alias toutes les colonnes comme col1, col2 ... etc. est nécessaire là-bas.
Amit Naidu
18
Avec les nouvelles versions des outils client, il existe plusieurs options pour formater la sortie de la requête. Le reste consiste à le spouler dans un fichier ou à enregistrer la sortie sous forme de fichier en fonction de l'outil client. Voici quelques moyens:
SQL * Plus
En utilisant les commandes SQL * Plus, vous pouvez formater pour obtenir la sortie souhaitée. Utilisez SPOOL pour spouler la sortie dans un fichier.
Vous pouvez également utiliser le nouvel indice dans SQL Developer ./*csv*/
/*csv*/
Par exemple, dans ma version de développeur SQL 3.2.20.10 :
Vous pouvez maintenant enregistrer la sortie dans un fichier.
Développeur SQL version 4.1
Nouveau dans SQL Developer version 4.1, utilisez ce qui suit comme la commande sqlplus et exécutez-le en tant que script. Pas besoin de l'indication dans la requête.
SET SQLFORMAT csv
Vous pouvez maintenant enregistrer la sortie dans un fichier.
Je sais que c'est un vieux fil, mais j'ai remarqué que personne n'a mentionné l'option de soulignement, qui peut supprimer les soulignements sous les en-têtes de colonne.
set pagesize 50000--50k is the max as of 12cset linesize 10000set trimspool on--remove trailing blankspacesset underline off--remove the dashes/underlines under the col headersset colsep ~select*from DW_TMC_PROJECT_VW;
Belle prise sur l'option de soulignement, en avait besoin.
knockando le
C'est bien si vous voulez un csv avec une ligne du haut contenant le titre / les en-têtes de chaque colonne. Cela aiderait tous ceux qui voudraient voir le fichier csv, et comprendre ce qu'ils regardent, etc ...
Doc
10
C'est brut, mais:
set pagesize 0 linesize 500 trimspool on feedback off echo offselect'"'|| empno ||'","'|| ename ||'","'|| deptno ||'"'as text
from emp
spool emp.csv
/
spool off
Vous pouvez formater explicitement la requête pour produire une chaîne délimitée avec quelque chose du type:
select'"'||foo||'","'||bar||'"'from tab
Et configurez les options de sortie comme il convient. En option, la variable COLSEP sur SQLPlus vous permettra de produire des fichiers délimités sans avoir à générer explicitement une chaîne avec les champs concaténés. Cependant, vous devrez mettre des guillemets autour des chaînes sur toutes les colonnes pouvant contenir des virgules incorporées.
J'ai écrit une fois un petit script SQL * Plus qui utilise dbms_sqlet dbms_outputpour créer un csv (en fait un ssv). Vous pouvez le trouver sur mon référentiel githup .
Vous devez savoir que les valeurs des champs peuvent contenir des virgules et des guillemets, de sorte que certaines des réponses suggérées ne fonctionneront pas, car le fichier de sortie CSV ne serait pas correct. Pour remplacer les guillemets dans un champ et le remplacer par le caractère guillemet double, vous pouvez utiliser la fonction REMPLACER fournie par oracle, pour changer un guillemet simple en guillemet double.
set echo offset heading offset feedback offset linesize 1024-- or some other value, big enoughset pagesize 50000set verify offset trimspool on
spool output.csv
select trim('"'|| replace(col1,'"','""')||'","'|| replace(col2,'"','""')||'","'|| replace(coln,'"','""')||'"')-- etc. for all the columnsfrom yourtable
/
spool off
Ou, si vous voulez le caractère guillemet simple pour les champs:
set echo offset heading offset feedback offset linesize 1024-- or some other value, big enoughset pagesize 50000set verify offset trimspool on
spool output.csv
select trim('"'|| replace(col1,'''','''''')||'","'|| replace(col2,'''','''''')||'","'|| replace(coln,'''','''''')||'"')-- etc. for all the columnsfrom yourtable
/
spool off
Utilisez vi ou vim pour écrire le sql, utilisez colsep avec un control-A (dans vi et vim précèdent le ctrl-A avec un ctrl-v). Assurez-vous de définir la taille des lignes et la taille des pages sur quelque chose de rationnel et activez le trimspool et le trimout.
spoolez-le dans un fichier. Ensuite...
sed -e 's/,/;/g'-e 's/ *{ctrl-a} */,/g'{spooled file}> output.csv
Cette chose sed peut être transformée en script. Le "*" avant et après le ctrl-A supprime tous les espaces inutiles. N'est-ce pas génial qu'ils se soient donné la peine d'activer la sortie html de sqlplus mais PAS de csv natif ?????
Je le fais de cette façon car il gère les virgules dans les données. Je les transforme en points-virgules.
Il y a un problème lors de l'utilisation de sqlplus pour créer des fichiers csv. Si vous voulez les en-têtes de colonne une seule fois dans la sortie et qu'il y a des milliers ou des millions de lignes, vous ne pouvez pas définir une taille de page suffisamment grande pour ne pas avoir de répétition. La solution est de commencer par pagesize = 50 et d'analyser les en-têtes, puis de relancer la sélection avec pagesize = 0 pour obtenir les données. Voir le script bash ci-dessous:
#!/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/nullset 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/nullset 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
}
Réponses:
Si vous utilisez 12.2, vous pouvez simplement dire
la source
Vous pouvez également utiliser ce qui suit, même s'il introduit des espaces entre les champs.
La sortie sera comme:
Ce serait beaucoup moins fastidieux que de taper tous les champs et de les concaténer avec des virgules. Vous pouvez poursuivre avec un simple script sed pour supprimer les espaces qui apparaissent avant une virgule, si vous le souhaitez.
Quelque chose comme ça pourrait fonctionner ... (mes compétences sed sont très rouillées, donc cela nécessitera probablement du travail)
la source
set pagesize 1000
lieu de 0. Dans mon commentaire précédent, vous ne pouvez pas rediriger vers le même fichier:cat myfile.csv | sed -e 's/[ \t]*|/|/g ; s/|[ ]*/|/g' > my_other_file.csv
.grep
ettr
comme çagrep -v -- ----- myfile.csv | tr -d [:blank:] > myfile.csv
.J'utilise cette commande pour les scripts qui extrait des données pour les tables dimensionnelles (DW). Donc, j'utilise la syntaxe suivante:
Et fonctionne. Je n'utilise pas sed pour formater le fichier de sortie.
la source
Je vois un problème similaire ...
J'ai besoin de spouler le fichier CSV à partir de SQLPLUS, mais la sortie a 250 colonnes.
Ce que j'ai fait pour éviter le formatage de la sortie SQLPLUS ennuyeux:
le problème est que vous perdrez les noms d'en-tête de colonne ...
vous pouvez ajouter ceci:
Je sais que c'est un peu hardcore, mais ça marche pour moi ...
la source
||
d'une sous-requête aussi?, je ne pense pas que ce soit nécessaire pour les sous-requêtes. mais oui, il est requis pour la sélection principale.select x
? Cela devrait fonctionner sans cela. @davidb, vous avez raison de dire que la concaténation n'est pas requise dans la sous-requête interne principale, mais alias toutes les colonnes comme col1, col2 ... etc. est nécessaire là-bas.Avec les nouvelles versions des outils client, il existe plusieurs options pour formater la sortie de la requête. Le reste consiste à le spouler dans un fichier ou à enregistrer la sortie sous forme de fichier en fonction de l'outil client. Voici quelques moyens:
En utilisant les commandes SQL * Plus, vous pouvez formater pour obtenir la sortie souhaitée. Utilisez SPOOL pour spouler la sortie dans un fichier.
Par exemple,
Vous pouvez également utiliser le nouvel indice dans SQL Developer .
/*csv*/
Par exemple, dans ma version de développeur SQL 3.2.20.10 :
Vous pouvez maintenant enregistrer la sortie dans un fichier.
Nouveau dans SQL Developer version 4.1, utilisez ce qui suit comme la commande sqlplus et exécutez-le en tant que script. Pas besoin de l'indication dans la requête.
Vous pouvez maintenant enregistrer la sortie dans un fichier.
la source
Je sais que c'est un vieux fil, mais j'ai remarqué que personne n'a mentionné l'option de soulignement, qui peut supprimer les soulignements sous les en-têtes de colonne.
la source
C'est brut, mais:
la source
Vous pouvez formater explicitement la requête pour produire une chaîne délimitée avec quelque chose du type:
Et configurez les options de sortie comme il convient. En option, la variable COLSEP sur SQLPlus vous permettra de produire des fichiers délimités sans avoir à générer explicitement une chaîne avec les champs concaténés. Cependant, vous devrez mettre des guillemets autour des chaînes sur toutes les colonnes pouvant contenir des virgules incorporées.
la source
préférez utiliser "set colsep" dans l'invite sqlplus au lieu d'éditer le nom de la colonne un par un. Utilisez sed pour modifier le fichier de sortie.
la source
J'ai écrit une fois un petit script SQL * Plus qui utilise
dbms_sql
etdbms_output
pour créer un csv (en fait un ssv). Vous pouvez le trouver sur mon référentiel githup .la source
Vous devez savoir que les valeurs des champs peuvent contenir des virgules et des guillemets, de sorte que certaines des réponses suggérées ne fonctionneront pas, car le fichier de sortie CSV ne serait pas correct. Pour remplacer les guillemets dans un champ et le remplacer par le caractère guillemet double, vous pouvez utiliser la fonction REMPLACER fournie par oracle, pour changer un guillemet simple en guillemet double.
Ou, si vous voulez le caractère guillemet simple pour les champs:
la source
trim()
n'est pas nécessaire.Utilisez vi ou vim pour écrire le sql, utilisez colsep avec un control-A (dans vi et vim précèdent le ctrl-A avec un ctrl-v). Assurez-vous de définir la taille des lignes et la taille des pages sur quelque chose de rationnel et activez le trimspool et le trimout.
spoolez-le dans un fichier. Ensuite...
Cette chose sed peut être transformée en script. Le "*" avant et après le ctrl-A supprime tous les espaces inutiles. N'est-ce pas génial qu'ils se soient donné la peine d'activer la sortie html de sqlplus mais PAS de csv natif ?????
Je le fais de cette façon car il gère les virgules dans les données. Je les transforme en points-virgules.
la source
Il y a un problème lors de l'utilisation de sqlplus pour créer des fichiers csv. Si vous voulez les en-têtes de colonne une seule fois dans la sortie et qu'il y a des milliers ou des millions de lignes, vous ne pouvez pas définir une taille de page suffisamment grande pour ne pas avoir de répétition. La solution est de commencer par pagesize = 50 et d'analyser les en-têtes, puis de relancer la sélection avec pagesize = 0 pour obtenir les données. Voir le script bash ci-dessous:
la source
J'ai écrit ce script purement SQLPlus pour vider les tables en CSV en 1994.
Comme indiqué dans les commentaires du script, quelqu'un chez Oracle a mis mon script dans une note de support Oracle, mais sans attribution.
https://github.com/jkstill/oracle-script-lib/blob/master/sql/dump.sql
Le script crée également un fichier de contrôle et un fichier de paramètres pour SQL * LOADER
la source
la source
Vous pouvez utiliser un indice csv. Consultez l'exemple suivant:
la source