sqlplus to csv scientific number conversion - oracle

I have the following in Unix under my shell script:
SET linesize 2000
SET pagesize 50000
SET ECHO OFF
SET FEEDBACK OFF
SET VERIFY OFF
SET MARKUP HTML OFF
set numwidth 17
set colsep ","
select accountnum, cardnum, name, address, number from employee;
Once it generates the output in .csv, cardnum and accountnum becomes scientific like:
5.30706E+15
I want it to be:
501889176278289
I know how to change it in Excel but since I am sending these reports to a client. I want it to go to them in the correct format so they don't have to change anything.

I would suggest this:
SELECT TO_CHAR(accountnum,'9999999999999999999') accountnum
, TO_CHAR(cardnum,'9999999999999999999') cardnum
, name, address, number
FROM employee;

Except of TO_CHAR suggested in other answer you can try:
set numformat 9999999999999999999 that should solve your problem.
Another way is COLUMN accountnum FORMAT 9999999999999999999

Related

Oracle spool issues

currently i use below code to spool csv file but i have find some line length more than 4000 characters , so it will no propey display
set echo off
set feedback off
set heading on
set linesize 32000
set pagesize 0
set termout off
set trim off
set trimspool on
set array 100
set underline off
set wrap off
set flush off
set verify off
set embedded on
select cloumnA||','||ColumnB ||','||ColumnC ..... from my_tab_name ;
so i modify my code but the result is not my want.
set echo off
set feedback off
set heading on
set linesize 32000
set pagesize 0
set termout off
set trim off
set trimspool on
set array 100
set underline off
set wrap off
set flush off
set verify off
set embedded on
select cloumnA,ColumnB ,ColumnC ..... from my_tab_name ;
the result 1:
A_value,B_value,C_value..... (the result is correct ,but only can show 4000 characters)
the result 2:
A_value
B_value
C_value
....
Anyone can help,thanks a lot!
When you concatenate columns (cloumnA||','||ColumnB ||','||ColumnC), the result is a VARCHAR2, which can't be more than 4000 characters (in typical circumstances).
See this similar question for some different options.
You could use COLSEP:
set colsep ','
spool myfile.csv
select cloumnA,ColumnB,ColumnC ..... from my_tab_name;
Which will get you something like
A_value ,B_value ,C_value
A_value ,B_value ,C_value
A_value ,B_value ,C_value
Which most people don't like, but it doesn't have a 4000-character line limit.
If you're using SQL Developer, you can use the easy /*csv*/ hint
select /*csv*/ cloumnA,ColumnB,ColumnC ..... from my_tab_name;
And if it's possible for you to use the newer SQLcl instead of SQL*Plus, you can use set sqlformat:
set sqlformat csv
spool myfile.csv
select cloumnA,ColumnB,ColumnC ..... from my_tab_name;

SQL Plus: How to prevent the auto rounding of the number

I have a requirement to pull the Oracle db values to csv using SQL Plus to compare a numeric values which has a decimal point of 10 digits.
But the the numbers are rounding automatically to 8 decimal point. Is there any way we can disable the rounding of numbers in SQLPlus. Below find the details.
Here is my SQL Set commands.
SET UNDERLINE OFF
SET PAGESIZE 50000
SET NEWPAGE NONE
SET WRAP OFF
SET COLSEP , -- SEPARATE COLUMNS WITH A COMMA
SET FEEDBACK OFF
SET TRIMS ON
SET TRIMSPOOL ON
SET DEFINE ON
SET termout ON
SET verify ON
SET linesize 600
Can somebody help me on this.
Numeric values don't have any intrinsic format, so your client is deciding how to display them. I'm not sure which client is producing the 'DB' values, but the SQL*Plus ones are just using its defaults:
SQL*Plus normally displays numbers with as many digits as are required for accuracy, up to a standard display width determined by the value of the NUMWIDTH variable of the SET command (normally 10). If a number is larger than the value of SET NUMWIDTH, SQL*Plus rounds the number up or down to the maximum number of characters allowed if possible, or displays hashes if the number is too large.
So you see:
with your_table (x, y) as (
select -0.0224231886, -0.021470109 from dual
union all select -0.037164512, -0.0238026527 from dual
union all select 0.021786217, 0.044550243 from dual
union all select 0.0772262609, 0.0724136521 from dual
union all select 0.968632046, 0.0866250777 from dual
)
select x, y from your_table;
X, Y
-.02242319,-.02147011
-.03716451,-.02380265
.021786217,.044550243
.077226261,.072413652
.968632046,.086625078
You can change the default for your session with `set numf[ormat]', using a format model with enough digits before and after the decimal point to represent any number you might have stored, e.g.:
set numformat 990.99999999999
then the same query gets
X, Y
-0.0224231886, -0.0214701090
-0.0371645120, -0.0238026527
0.0217862170, 0.0445502430
0.0772262609, 0.0724136521
0.9686320460, 0.0866250777
Or you could implicitly modify it using set numw[idth]:
set numf ""
set numwidth 20
X, Y
-.0224231886, -.021470109
-.037164512, -.0238026527
.021786217, .044550243
.0772262609, .0724136521
.968632046, .0866250777
which gives you the precision you need, but doesn't show the leading zero. If that doesn't matter then this approach is simpler.
Perhaps you seek for column formating option to enforce column formating
COLUMN column_name FORMAT 999999.0000000000

SQL Developer script output to datagrid

In Oracle SQL Developer, I can get simple query results returned in the 'Query Results' grid, but if I need to use variable in script, I need to use the 'Run Script' option and my results show up in 'Script Output' window, and I can't export it to csv format. Here is my sample code:
var CatCode char(5) ;
exec :CatCode := 'ZK';
SELECT * FROM Products WHERE CategoryCode = :CatCode;
Any help would be appreciated.
Thanks.
Just add a /*csv*/ to your query, the tool will bring back the output in CSV automatically when executed as a script (F5).
Or use a substitution variable instead. &Var vs :Var, run with F9, SQLDev will prompt you for the value.
VAR stcode CHAR(2);
EXEC :stcode := 'NC';
SELECT /*csv*/
*
FROM
untappd
WHERE
venue_state =:stcode;
Or to go straight to the grid so you can use can use the Grid Export feature.
SELECT
*
FROM
untappd
WHERE
venue_state =:stcode2;
Execute with Ctrl+Enter or F9
Supply the input parameter in the pop up dialog, click OK.
Shazaam.
Here you go you can run this one to be ensure. it's running.
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 C:\Users\**direcotory**\sql\Test1.csv; --this is file path to save data
var CatCode char(5) ;
exec :CatCode := 'ZK';
SELECT * FROM Products WHERE CategoryCode = :CatCode;
spool off;
Thanks #thatjeffsmith and Paras, spool option gave me new direction and it worked. I slightly changed your code and it works great.
var CatCode char(5) ;
exec :CatCode := 'ZK';
set feedback off;
SET SQLFORMAT csv;
spool "c:\temp\spoolTest.csv"
SELECT * FROM Products WHERE CategoryCode = :CatCode;
spool off;
SET SQLFORMAT;
set feedback on;

Header formatting while spooling a csv file in sqlplus

I am required to spool a csv from a table in Oracle, using sqlplus. Following is the format required:
"HOST_SITE_TX_ID","SITE_ID","SITETX_TX_ID","SITETX_HELP_ID"
"664436565","16","2195301","0"
"664700792","52","1099970","0"
Following is the relevant piece of the shell script I wrote:
sqlplus -s $sql_user/$sql_password#$sid << eof >> /dev/null
set feedback off
set term off
set linesize 1500
set pagesize 11000
--set colsep ,
--set colsep '","'
set trimspool on
set underline off
set heading on
--set headsep $
set newpage none
spool "$folder$filename$ext"
select '"'||PCL_CARRIER_NAME||'","'||SITETX_EQUIP_ID||'","'||SITETX_SITE_STAT||'","'||SITETX_CREATE_DATE||'","'||ADVTX_VEH_WT||'"'
from cvo_admin.MISSING_HOST_SITE_TX_IDS;
spool off
(I have used some commented statements in, to signify the things that I tried but couldn't get to work)
The output I receive is:
'"'||PCL_CARRIER_NAME||'","'||SITETX_EQUIP_ID||'","'||SITETX_SITE_STAT||'","'||SITETX_CREATE_DATE||'","'||ADVTX_VEH_WT||'"'
"TRANSPORT INC","113","00000000","25-JAN-13 10.17.51 AM",""
"TRANSPORT INC","1905","00000000","25-JAN-13 05.06.44 PM","0"
Which shows that the header is messed up - it is literally printing the whole string that should have been interpreted as an sql statement, as is the case with the data displayed.
Options I am considering:
1) Using colsep
set colsep '","'
spool
select * from TABLE
spool off
This introduces other problems as the data having leading and trailing spaces, first and the last values in the files are not enclosed by quotes
HOST_SITE_TX_ID"," SITE_ID"
" 12345"," 16"
" 12345"," 21
I concluded that this method gives me more heartburn than the one I described earlier.
2) Getting the file and use a regex to modify the header.
3) Leaving the header altogether and manually adding a header string at the beginning of the file, using a script
Option 2 is more doable, but I was still interested in asking, if there might be a better way to format the header somehow, so it comes in a regular csv, (comma delimited, double quote bounded) format.
I am looking to do as less hard coding as possible - the table I am exporting has around 40 columns and I am currently running the script for around 4 million records - breaking them in a batch of around 10K each. I would really appreciate any suggestions, even totally different from my approach - I am a programmer in learning.
One easy way to have a csv with just one header is to do
set embedded on
set pagesize 0
set colsep '|'
set echo off
set feedback off
set linesize 1000
set trimspool on
set headsep off
the embedded is a hidden option but it is important to have JUST one header
This is how I created a header:
set heading off
/* header */
SELECT '"'||PCL_CARRIER_NAME||'","'||SITETX_EQUIP_ID||'","'||SITETX_SITE_STAT||'","'||SITETX_CREATE_DATE||'","'||ADVTX_VEH_WT||'"'
FROM
(
SELECT 'PCL_CARRIER_NAME' AS PCL_CARRIER_NAME
, 'SITETX_EQUIP_ID' AS SITETX_EQUIP_ID
, 'SITETX_SITE_STAT' AS SITETX_SITE_STAT
, 'SITETX_CREATE_DATE' AS SITETX_CREATE_DATE
, 'ADVTX_VEH_WT' AS ADVTX_VEH_WT
FROM DUAL
)
UNION ALL
SELECT '"'||PCL_CARRIER_NAME||'","'||SITETX_EQUIP_ID||'","'||SITETX_SITE_STAT||'","'||SITETX_CREATE_DATE||'","'||ADVTX_VEH_WT||'"'
FROM
(
/* first row */
SELECT to_char(123) AS PCL_CARRIER_NAME
, to_char(sysdate, 'yyyy-mm-dd') AS SITETX_EQUIP_ID
, 'value3' AS SITETX_SITE_STAT
, 'value4' AS SITETX_CREATE_DATE
, 'value5' AS ADVTX_VEH_WT
FROM DUAL
UNION ALL
/* second row */
SELECT to_char(456) AS PCL_CARRIER_NAME
, to_char(sysdate-1, 'yyyy-mm-dd') AS SITETX_EQUIP_ID
, 'value3' AS SITETX_SITE_STAT
, 'value4' AS SITETX_CREATE_DATE
, 'value5' AS ADVTX_VEH_WT
FROM DUAL
) MISSING_HOST_SITE_TX_IDS;
This is how you add a pipe delimited header to SQL statements. Once you spool it out that "something" wont be there
-- this creates the header
select 'header_column1|header_column2|header_column3' as something
From dual
Union all
-- this is where you run the actual sql statement with pipes in it
select
rev.value1 ||'|'||
rev.value2 ||'|'||
'related_Rel' as something
from
...
In Oracle 19 you can use set markup csv on to ensure that csv outputs are created.
You can also set the delimiter and optional quote or even spool html if you prefer
You can read more here
set markup csv on
spool "$folder$filename$ext"
select q'|wow, I can't beleive he said "hello, how are you?", can you beleive it!|' as text
from dual;
spool off
quit;

Oracle - dynamic column name in select statement

Question:
Is it possible to have a column name in a select statement changed based on a value in it's result set?
For example, if a year value in a result set is less than 1950, name the column OldYear, otherwise name the column NewYear. The year value in the result set is guaranteed to be the same for all records.
I'm thinking this is impossible, but here was my failed attempt to test the idea:
select 1 as
(case
when 2 = 1 then "name1";
when 1 = 1 then "name2")
from dual;
You can't vary a column name per row of a result set. This is basic to relational databases. The names of columns are part of the table "header" and a name applies to the column under it for all rows.
Re comment: OK, maybe the OP Americus means that the result is known to be exactly one row. But regardless, SQL has no syntax to support a dynamic column alias. Column aliases must be constant in a query.
Even dynamic SQL doesn't help, because you'd have to run the query twice. Once to get the value, and a second time to re-run the query with a different column alias.
The "correct" way to do this in SQL is to have both columns, and have the column that is inappropriate be NULL, such as:
SELECT
CASE WHEN year < 1950 THEN year ELSE NULL END AS OldYear,
CASE WHEN year >= 1950 THEN year ELSE NULL END AS NewYear
FROM some_table_with_years;
There is no good reason to change the column name dynamically - it's analogous to the name of a variable in procedural code - it's just a label that you might refer to later in your code, so you don't want it to change at runtime.
I'm guessing what you're really after is a way to format the output (e.g. for printing in a report) differently depending on the data. In that case I would generate the heading text as a separate column in the query, e.g.:
SELECT 1 AS mydata
,case
when 2 = 1 then 'name1'
when 1 = 1 then 'name2'
end AS myheader
FROM dual;
Then the calling procedure would take the values returned for mydata and myheader and format them for output as required.
You will need something similar to this:
select 'select ' || CASE WHEN YEAR<1950 THEN 'OLDYEAR' ELSE 'NEWYEAR' END || ' FROM TABLE 1' from TABLE_WITH_DATA
This solution requires that you launch SQLPLUS and a .sql file from a .bat file or using some other method with the appropriate Oracle credentials. The .bat file can be kicked off manually, from a server scheduled task, Control-M job, etc...
Output is a .csv file. This also requires that you replace all commas in the output with some other character or risk column/data mismatch in the output.
The trick is that your column headers and data are selected in two different SELECT statements.
It isn't perfect, but it does work, and it's the closest to standard Oracle SQL that I've found for a dynamic column header outside of a development environment. We use this extensively to generate recurring daily/weekly/monthly reports to users without resorting to a GUI. Output is saved to a shared network drive directory/Sharepoint.
REM BEGIN runExtract1.bat file -----------------------------------------
sqlplus username/password#database #C:\DailyExtracts\Extract1.sql > C:\DailyExtracts\Extract1.log
exit
REM END runExtract1.bat file -------------------------------------------
REM BEGIN Extract1.sql file --------------------------------------------
set colsep ,
set pagesize 0
set trimspool on
set linesize 4000
column dt new_val X
select to_char(sysdate,'MON-YYYY') dt from dual;
spool c:\DailyExtracts\&X._Extract1.csv
select '&X-Project_id', 'datacolumn2-Project_Name', 'datacolumn3-Plant_id' from dual;
select
PROJ_ID
||','||
replace(PROJ_NAME,',',';')-- "Project Name"
||','||
PLANT_ID-- "Plant ID"
from PROJECTS
where ADDED_DATE >= TO_DATE('01-'||(select to_char(sysdate,'MON-YYYY') from dual));
spool off
exit
/
REM ------------------------------------------------------------------
CSV OUTPUT (opened in Excel and copy/pasted):
old 1: select '&X-Project_id' 'datacolumn2-Project_Name' 'datacolumn3-Plant_id' from dual
new 1: select 'MAR-2018-Project_id' 'datacolumn2-Project_Name' 'datacolumn3-Plant_id' from dual
MAR-2018-Project_id datacolumn2-Project_Name datacolumn3-Plant_id
31415 name1 1007
31415 name1 2032
32123 name2 3302
32123 name2 3384
32963 name3 2530
33629 name4 1161
34180 name5 1173
34180 name5 1205
...
...
etc...
135 rows selected.

Resources