SQL*Plus ignores colsep option - oracle

So we are trying to dump the content of our oracle database to a .CSV file but when executing the following command
set colsep ',' echo off newpage 0 space 0 pagesize 0 linesize 3000 feed off head off trimspool on
spool C:\Users\whocares\Desktop\test.CSV
select ID, LOCATION_ID from club;
spool off
the output looks as follows:
...
17499 902
17500 902
17501 902
17502 902
17503 902
17504 902
17505 902
17506 902
17507 902
17508 902
17509 902
...
and sqlplus seems to completely ignore the set colsep ',' option.
To get a valid csv output we need to have the output look like this:
...
17499,902
17500,902
17501,902
17502,902
17503,902
17504,902
17505,902
17506,902
17507,902
17508,902
17509,902
...
So how do you properly use the set colsep option?
We don't have much experience with sqlplus and for some reason other stackoverflow solutions didn't seem to work for us.

SET COLSEP replaces SET SPACE, and that's so since Oracle 9.2 (see Obsolete SQL*Plus Commands).
If you use them both, there's no separator:
SQL> set colsep ','
SQL> select * from dept where rownum = 1;
DEPTNO,DNAME ,LOC
----------,--------------------,--------------------
10,ACCOUNTING ,NEW YORK
SQL> set space 0
SQL> select * from dept where rownum = 1;
DEPTNODNAME LOC
--------------------------------------------------
10ACCOUNTING NEW YORK
SQL> set space 1
SQL> select * from dept where rownum = 1;
DEPTNO DNAME LOC
---------- -------------------- --------------------
10 ACCOUNTING NEW YORK
SQL>
So - remove SET SPACE.
Another option is to concatenate columns. Yes, that's a tedious job but it works, e.g.
SQL> select deptno ||','|| dname ||','|| loc from dept;
DEPTNO||','||DNAME||','||LOC
---------------------------------------------------------------
10,ACCOUNTING,NEW YORK
20,RESEARCH,DALLAS
30,SALES,CHICAGO
40,OPERATIONS,BOSTON
SQL>
If there are many tables involved, you could write a query which will write a query for you:
SQL> select 'select ' || listagg(column_name, '||'',''||') within group (order by column_id) ||
2 ' from ' || table_name result
3 from user_tab_columns
4 where table_name = 'DEPT'
5 group by table_name;
RESULT
--------------------------------------------------------------------------------
select DEPTNO||','||DNAME||','||LOC from DEPT
SQL>
Now just copy/paste the result and run it.

Related

How to store and retrieve data from temp table

I am new to PL-SQL. Please can someone help me on wrapping the below.
I need to:
Copy contents of table A and store in global temp table
Do an update on Table A & other tasks
Revert contents of Table A from global temp table
Delete temp table
ANy help is much appreciated.
Here you are:
Sample tables:
SQL> create table test as select * from dept;
Table created.
SQL> create global temporary table gtt_test as
2 select * from test where 1 = 2;
Table created.
SQL> select * from test;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
1 Dept 1 NY
2 Dept 2 London
6 rows selected.
SQL> select * from gtt_test;
no rows selected
Anonymous PL/SQL block which does what you asked:
SQL> begin
2 -- copy contents ...
3 insert into gtt_test select * from test;
4
5 -- update A
6 update test set loc = 'blabla';
7 delete from test where deptno = 20;
8
9 -- revert
10 delete from test;
11 insert into test select * from gtt_test;
12
13 -- delete temp
14 delete from gtt_test;
15 end;
16 /
PL/SQL procedure successfully completed.
At the end, no changes whatsoever:
SQL> select * from test;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
1 Dept 1 NY
2 Dept 2 London
6 rows selected.
SQL> select * from gtt_test;
no rows selected
SQL>
[EDIT]
Query you posted as a comment isn't correct; dynamic SQL must be enclosed into single quotes, it must not be terminated by a semi-colon while all other statements must. Fixed, it should be
BEGIN
EXECUTE IMMEDIATE 'create table camel_route_temp as '
|| ' select * from acquire.CAMEL_ROUTE_PROCESS';
DBMS_OUTPUT.put_line ('Temp table created');
--update A
UPDATE acquire.camel_route_process
SET acquire = 'DISABLED',
assure = 'DISABLED',
validation = 'DISABLED',
report = 'DISABLED',
notification = 'DISABLED';
COMMIT;
DBMS_OUTPUT.put_line ('Aquire components disabled');
END;
/

How to fetch odd columns in oracle

How to fetch odd columns in Oracle using a query when number of columns and name of columns are not known?
E.g.:
I need to get output in below format
Column1 column3 column5 column7
And so on....
You need to use the dynamic queries in the procedure as follows:
SQL> CREATE OR REPLACE PROCEDURE ODD_COLUMNS (
2 TABLE_NAME_P IN VARCHAR2,
3 DATAA OUT SYS_REFCURSOR
4 ) AS
5 V_SQL VARCHAR2(4000);
6 BEGIN
7 SELECT
8 'SELECT '
9 ||
10 LISTAGG(COLUMN_NAME, ',') WITHIN GROUP(
11 ORDER BY
12 COLUMN_ID
13 )
14 || ' FROM "'
15 || TABLE_NAME_P
16 || '"'
17 INTO V_SQL
18 FROM
19 USER_TAB_COLS
20 WHERE
21 TABLE_NAME = TABLE_NAME_P
22 AND MOD(COLUMN_ID, 2) = 1;
23
24 OPEN DATAA FOR V_SQL;
25
26 END ODD_COLUMNS;
27 /
Procedure created.
SQL>
Now, Let's test it:
SQL> variable rc refcursor;
SQL> exec ODD_COLUMNS('EMP',:rc);
PL/SQL procedure successfully completed.
SQL> print rc;
EMP_ID E
---------- -
10 N
20 Y
SQL>
SQL> exec ODD_COLUMNS('MY_TABLE1',:rc);
PL/SQL procedure successfully completed.
SQL> print rc;
ID REQ_QTY
---------- ----------
1001 10
1001 20
1001 30
1002 40
1003 10
1003 20
6 rows selected.
SQL>
Cheers!!
This cannot be done simply, but it is possible using the Oracle data dictionary and some dynamic SQL.
To find out the odd-numbered columns you need to look at the ALL_TAB_COLUMNS view. Column COLUMN_ID sequences the columns 1,2,3. So this will find all the odd-numbered columns in the SCOTT.EMP table:
select column_name, column_id
from all_tab_columns
where owner = 'SCOTT'
and table_name = 'EMP'
and mod(column_id,2) = 1
order by column_id;
This will return something like:
COLUMN_NAME COLUMN_ID
----------- ---------
EMPNO 1
JOB 3
HIREDATE 5
COMM 7
We can use the LISTAGG function to make that into a comma-separated list:
select listagg(column_name,',') within group (order by column_id) as result
from user_tab_columns
where table_name = 'EMP'
and mod(column_id,2) = 1;
RESULT
------
EMPNO,JOB,HIREDATE,COMM
Now we can add to that SQL to generate the select statement you want:
select 'select ' || listagg(column_name,',') within group (order by column_id) || ' from ' || table_name as sql
from user_tab_columns
where table_name = 'EMP'
and mod(column_id,2) = 1
group by table_name;
SQL
---
select EMPNO,JOB,HIREDATE,COMM from EMP
(Note I had to add a group by clause because table_name is not being aggregated by LISTAGG).
You could use that SQL within some PL/SQL code to populate a variable v_sql, then use the DBMS_SQL package to run it. But that is a complex topic in itself and I won't go into it here.

CLEAR COLUMNS Definition

I'am confused on this function clear columns. Some one can explain to me this one.
I'am using this in my script.
clear columns
COLUMN temp_in_statement new_value str_in_statement
SELECT DISTINCT
LISTAGG('''' || MONTHCOVERED || ''' AS ' || to_char(MONTHCOVERED,'MONDDYYYY'),',')
WITHIN GROUP (ORDER BY MONTHCOVERED) AS temp_in_statement
FROM (SELECT DISTINCT trunc(MONTHCOVERED) as MONTHCOVERED FROM bbsm_aaa where trunc(MONTHCOVERED) between '01-AUG-19' and '31-OCT-19');
Is there specific column/s that are cleared on this? Or all columns that I assigned was also deleted?
HELP is there for a reason :)
SQL> help clear
CLEAR
-----
Resets or erases the current value or setting for the specified option.
CL[EAR] option ...
where option represents one of the following clauses:
BRE[AKS]
BUFF[ER]
COL[UMNS]
COMP[UTES]
SCR[EEN]
SQL
TIMI[NG]
SQL>
This isn't related to columns' contents, but the way they are formatted in SQL*Plus. Have a look at this example:
First, set some columns' settings using the col command:
SQL> col empno format 9999
SQL> col ename format a5
SQL> col sal format 999g990d00
SQL>
SQL> select empno, ename, sal from emp where rownum < 4;
EMPNO ENAME SAL
----- ----- -----------
7369 SMITH 920,00
7499 ALLEN 1.600,00
7521 WARD 1.250,00
Now, clear those settings and see the difference:
SQL> clear col
columns cleared
SQL> select empno, ename, sal from emp where rownum < 4;
EMPNO ENAME SAL
---------- ---------- ----------
7369 SMITH 920
7499 ALLEN 1600
7521 WARD 1250
SQL>
As you can see, values in those columns weren't affected - only the way they are displayed.

Check if both column and table exist and run queries based on the result

I am trying to run some SQL queries on Oracle database, but before running the query I need to check if both table and column exists. If table exists and column does not exist, then run another query:
if table `testtable` exists and if table has column `testcolumn`
Run a SQL which returns the result
else if table `testtable` exists but column `testcolumn` not present
Run a different sql which also returns the result
else
print some defined string
You can use:
DECLARE
nCount NUMBER;
BEGIN
SELECT COUNT(*)
INTO nCount
FROM USER_TAB_COLS
WHERE TABLE_NAME = 'TESTTABLE' AND
COLUMN_NAME = 'TESTCOLUMN';
IF nCount > 0 THEN
-- Run a SQL which returns the result
ELSE
SELECT COUNT(*)
FROM USER_TABLES
WHERE TABLE_NAME = 'TESTTABLE';
IF nCount > 0 THEN
Run a different sql which also returns the result
ELSE
print some defined string
END;
You'll have to add code to run whatever SQL you're trying to run, and to print whatever message you need.
Best of luck.
Here's one option - check contents of USER_TAB_COLUMNS and - depending on what you find - use refcursor in order to return the result.
SQL> create or replace function f_test
2 return sys_refcursor
3 is
4 l_cnt number;
5 cur_r sys_refcursor;
6 begin
7 -- 1st test - this one fails
8 select count(*)
9 into l_cnt
10 from user_tab_columns
11 where table_name = 'EMP'
12 and column_name = 'DOES_NOT_EXIST';
13
14 if l_cnt > 0 then
15 open cur_r for select ename, job, sal from emp;
16 end if;
17
18 -- 2nd test - this one is OK
19 select count(*)
20 into l_cnt
21 from user_tab_columns
22 where table_name = 'DEPT'
23 and column_name = 'DEPTNO';
24
25 if l_cnt > 0 then
26 open cur_r for select dname, loc from dept;
27 end if;
28
29 return cur_r;
30 end;
31 /
Function created.
SQL> select f_test from dual;
F_TEST
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
DNAME LOC
-------------- -------------
ACCOUNTING NEW YORK
RESEARCH DALLAS
SALES CHICAGO
OPERATIONS BOSTON
SQL>
It has to be some kind of a dynamic code because you can't just write a static SELECT statement that selects non-existent columns as you'd get ORA-00904: "DOES_NOT_EXIST": invalid identifier error.

Why do I get SP2-0253

I am getting in my test. But I think linesize is already large enough. I know increase linesize will solve the issue. Please let me know why I am getting SP2-0253 here.
SQL> COLUMN sal HEADING 'Salary' FORMAT $99,999.99
SQL> set lines 10
SQL> show user
USER is "SCOTT"
SQL> desc sal from emp
Usage: DESCRIBE [schema.]object[#db_link]
SQL> select sal from emp where rownum = 1;
SP2-0253: data item 1 ("SAL") will not fit on line
SQL> set lines 20
SQL> /
Salary
-----------
$800.00
SQL>
1) show linesize to get the current linesize. My guess is "80".
2) set linesize 32767
3) Run your SQL command. Check the actual line size.
SP2-0253: data item 1 ("SAL") will not fit on line
The reason is simple. You want the output format as:
FORMAT $99,999.99
Which needs a linesize of 11 to be displayed with proper position and alignment in SQL*Plus output.
Let's see:
SQL> set linesize 11
SQL> select sal from emp where rownum = 1;
Salary
-----------
$800.00
The simplest way to see how many lines it takes in the output is to check the LENGTH of the underline:
SQL> select length('-----------') length from dual;
LENGTH
----------
11
SQL>
So, it answers the question "why the output of 11 lines can't fit in 10 lines".
Update The actual reason for the behaviour is that the column name is formatted as new column name and there is no correct alias provided in the select list.
COLUMN commands only apply to the column names in the SELECT list when matched exactly. If they differ, then you must use the exact alias in the column list in the select statement.
Solution Add same alias name as the column name provided int he format.
SQL> COLUMN sal HEADING 'Salary' FORMAT $99,999.99
SQL> set lines 10
SQL> show user
USER is "SCOTT"
SQL> select sal from emp where rownum = 1;
SP2-0253: data item 1 ("SAL") will not fit on line
SQL> select sal Salary from emp where rownum = 1;
SALARY
----------
800
SQL>
Alternatively,
SQL> set linesize 10
SQL> select sal Salary from emp where rownum = 1;
SALARY
----------
800
SQL> select sal as "Salary" from emp where rownum = 1;
Salary
----------
800
SQL> select sal from emp where rownum = 1;
SP2-0253: data item 1 ("SAL") will not fit on line
SQL> set linesize 11
SQL> select sal from emp where rownum = 1;
Salary
-----------
$800.00
SQL>
problem is not in format but in trailing sign for negative numbers. There is no number format to avoid this. Use to_char for select your data in required format in conjunction with substr to trim result to 10 characters

Resources