Getting query result as CSV in PL/SQL using exactly the same command as in SQL with hint - sql

I am able to get the result as CSV in Oracle by using this simple query with a hint.
SELECT /*csv*/ * FROM dual;
This returns
"DUMMY"
"X"
Now I would like to use exactly the same hint in PL/SQL in order not to reinvent the wheel.
SET SERVEROUTPUT ON;
declare
cur sys_refcursor;
csv_line varchar2(4000);
begin
open cur for select /*csv*/ * from dual;
loop
fetch cur into csv_line;
exit when cur%NOTFOUND;
dbms_output.put_line(csv_line);
end loop;
close cur;
end;
Unfortunately this prints only
X
which seems to ignore the hint.
Any way to do it that simple or do I have to write a special piece of code for exporting the data as CSV?

The /*csv*/ hint is specific to SQL Developer and it's sibling SQLCl; and is somewhat superseded by the set sqlformat csv option.
It is not a hint recognised by the optimiser; those are denoted by a plus sign, e.g. /*+ full(...) */ or less commonly --+ full(...).
If you're creating the output in PL/SQL you will need to construct the string yourself, adding the double quotes and delimiters. You can either have the cursor query do that so you can select into a single string even when you have multiple columns; or have a 'normal' query that selects into a record and have PL/SQL add the extra characters around each field as it's output.
It would be more normal to use utl_file than dbms_output as the client may not have that enabled anyway, but of course that writes to a directory on the server. If you're writing to a file on the client then PL/SQL may not be appropriate or necessary.
If you need to do some manipulation of the data in PL/SQL then one other option is to use a collection type and have an output/bind ref cursor, and then have SQL Developer print that as CSV. But you don't normally want to be too tied to a single client.

Related

Run an oracle SQL script twice with different parameters

I have an SQL statement in Oracle SQL developer that has some variables:
DEFINE custom_date = "'22-JUL-2016'" --run1
DEFINE custom_date = "'25-JUL-2016'" --run2
SELECT * FROM TABLE WHERE date=&custom_date
The real query is much more complicated and has many more variables and new tables are created from the results of the query. How can I create a script so that the query is executed twice, the first time with the custom date set as in the first line and the second time as in the second line.
In Oracle, the &variable is a "substitution variable" and is not part of SQL; it is part of the SQL*Plus scripting language (understood by SQL Developer, Toad etc.)
The better option, and what you are asking about, is BIND VARIABLES. The notation is :variable (with a colon : instead of &), for example :custom_date.
The difference is that a substitution variable is replaced by its value in the front-end application (SQL Developer in your case) before the query is ever sent to the Oracle engine proper. A bind variable is substituted at runtime. This has several benefits; discussing them is outside the scope of your question.
When you execute a query with bind variables in SQL Developer, the program will open a window where you enter the desired values for the bind variables. You will have to experiment with that a little bit till you can make it work (for example I never remember if a date must be entered with the single quotes or without). Good luck!
Define is used in TRANSACT SQL. To do this Oracle way, You can create anonymus PL/SQL block, similar to this:
DECLARE
p_param1 DATE;
p_param2 NUMBER;
CURSOR c_cur1(cp_param1 DATE,cp_param2 NUMBER)
IS
SELECT * FROM table WHERE date = cp_param1
;
BEGIN
-- Execute it first time
p_param1 := TO_DATE('2016-09-01','YYYY-MM-DD');
FOR r IN c_cur1(p_param1)
LOOP
NULL;
END LOOP;
-- Execute it second time
p_param1 := TO_DATE('2015-10-11','YYYY-MM-DD');
FOR r IN c_cur1(p_param1)
LOOP
NULL;
END LOOP;
END;
And in it, You create cursor with parameters and execute it twice with different parameter.
I do not know why You want to execute this query twice, so the script abowe does nothing with results, but it certainly should execute Your query twice, with different params.

Creating parameterized cursors in DB2

I'm Facing below error:
An unexpected token "(" was found following " CURSOR ". Expected tokens may include: "CURSOR". SQLSTATE=42601
And I'm just trying to create a simple cursor, actually the example one found here in IBM documentation.
Cursor declaration looks something like:
DECLARE
CURSOR c1 (max_wage NUMBER) IS
SELECT * FROM emp WHERE sal < max_wage;
Not sure if this is do to the version of DB2 being used or not. Can anyone suggest maybe an alternative to creating a parameterized cursor?
You are trying to use PL/SQL syntax in DB2. This requires changes to the server environment. If you want to support the Oracle datatypes as well, the database must be created with the right settings, too. See this article for more details. The summary of that article is:
Open a DB2 Command Window (in Administrator mode)
Run db2start
Run db2set DB2_COMPATIBILITY_VECTOR=ORA
Run db2set DB2_DEFERRED_PREPARE_SEMANTICS=YES
Run db2stop
Run db2start
Execute your PL/SQL statements, e.g. in a DB2 CLP (run db2 -tv) command window.
Note that you should run
SET SQLCOMPAT PLSQL; in your DB2 CLP before trying PL/SQL. This enables using a forward slash (/) as a PL/SQL statement terminator. You should then obviously also then actually terminate your command with a forward slash :)
Here's an example taken from your link, modified to work with the default SAMPLE database in DB2:
SET SQLCOMPAT PLSQL;
DECLARE
my_record emp%ROWTYPE;
CURSOR c1 (max_wage integer) IS
SELECT * FROM employee WHERE salary < max_wage;
BEGIN
OPEN c1(40000);
LOOP
FETCH c1 INTO my_record;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Name = ' || my_record.firstnme || ', salary = '
|| my_record.salary);
END LOOP;
CLOSE c1;
END;
/
If you don't want to do all the above, then use the standard DB2 cursor syntax:
DECLARE [cursor name] CURSOR FOR [...]
...but that doesn't support parameterized cursors. To do so, I'd recommend creating a stored procedure taking the parameter. This stored procedure can then create a cursor using that parameter directly in the SQL.

Any SIMPLE way to fetch ALL results from a PL/SQL cursor?

The second part of the question: How to do the same (get ALL results, without any loops) with SQL*Plus.
I'm writing some PL/SQL scripts to test the data integrity using Jenkins.
I'm having a script like this:
declare
temp_data SOME_PACKAGE.someRefCurFunction; // type: CURSOR
DATA1 NUMBER;
DATA2 NUMBER;
DATA3 SOMETHING.SOMETHING_ELSE%TYPE;
begin
cursor := SOME_PACKAGE.someFunction('some',parameters,here);
LOOP
FETCH cursor INTO DATA1,DATA2,DATA3;
EXIT WHEN temp_data%NOTFOUND;
dbms_output.put_line(DATA1||','||DATA2||','||DATA3);
END LOOP;
end;
Relsults look like this:
Something1,,Something2
Something3,Something4,Something5
Something6,Something7,Something8
Sometimes the results are null, as in the 1st line. It doesnt matter, they should be.
The purpose of this script is simple - to fetch EVERYTHING from the cursor, comma separate the data, and print lines with results.
The example here is simple as hell, but It's just and example. The "Real life" Packages contain sometimes hundreds of variables, processing enormous database tables.
I need it to be as simple as possible.
Is there any method to fetch EVERYTHING from the cursor, comma separate single results if possible, and send it to output? The final output in the Jenkins test should be a text file, to be able to diff it with other results.
Thanks in advance :)
If you're truly open to a SQL*Plus script, rather than a PL/SQL block
SQL> set colsep ','
SQL> variable rc refcursor;
SQL> exec :rc := SOME_PACKAGE.someFunction('some',parameters,here);
SQL> print rc;
should execute the procedure and fetch all the data from your cursor. You could spool the resulting CSV output to a file using the spool command. Of course, you then may encounter issues where SQL*Plus isn't displaying the data in a clean format because of the linesize or other similar issues-- that may force you to add some additional SQL*Plus formatting commands (i.e. set linesize, column <<column name>> format <<format>>, etc.)
It's not obvious to me that a SQL*Plus script buys you much over writing some dynamic SQL that generates the PL/SQL script that you posted initially or (if you're on 12c) writing some code that uses dbms_sql to fetch data from the cursor that is returned.
The answer seems obvious. You currently have a function which returns a cursor itself returning a data set of hundreds (tho you show only three) fields. You want instead a single string with the comma-separated values. So change the function or write another one based on the same query.
package body SOME_PACKAGE
...
-- The current function
function someFunction ...
returns ref_cursor ...
-- create cursor based on:
select f1, f2, f3 --> Three (or n) fields
from ...
where ...;
return generated_cursor;
end function;
-- The new function
function someOtherFunction ...
returns ref_cursor ...
-- create cursor based on:
select f1 || ',' || f2 || ',' || f3 as StringField --> one string field
from ...
where ...;
return generated_cursor;
end function;
end package;
This isn't quite all that you asked for. It does save declaring variables (one instead of hundreds) to read the data in one row at a time, but you still read it in one row at a time instead of, as I read your question, reading in every row in one operation. But if such a super-fetch were possible, it would require massive amounts of memory. Sometimes we do things that just require massive amounts of memory and we just work with that the best we can. But your "requirement" seems to be only a matter of convenience for the developers. That, imnsho, lies way down in the list of priorities for consuming resources.
Developing a cursor that returns the data in the final form you want would seem to me to the best of all alternatives.

PL/SQL, Cannot print variable

I'm trying to learn PL/SQL by simply assigning a variable from a select statement and then, to confirm it's working, print it sql output.
DECLARE ALLOW_STUFF NUMBER;
BEGIN
SELECT VAL_N INTO ALLOW_STUFF FROM MY_TABLE WHERE MY_KEY = 'ALLOW_ME';
DBMS_OUTPUT.PUT_LINE(ALLOW_STUFF);
END;
I'm using SQL Developer and/or SQL PLus. When I run this, all I get is
Anonymous block completed
Rather than than the value of MY_TABLE.VAL_N
You need to enable output, otherwise the DBMS_OUTPUT.PUT_LINE statements are ignored.
Output can be enabled using:
DBMS_OUTPUT.ENABLE();
For more information about DBMS_OUTPUT read Oracle documentation: http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_output.htm#i1000634
As stated in the comments also set serveroutput on can be used.

PostgreSQL cursors

I am trying to learn basic cursors using PostgreSQL. This is my script:
DECLARE cur_employees CURSOR FOR
SELECT *
FROM employee
CLOSE cur_employees
I want to traverse the list and output those which are active. Where should I start?
You very rarely want to explicitly use cursors at all in PostgreSQL, even when processing query results in plpgsql. This is a marked contrast from many other SQL databases where they are used almost all the time.
In plpgsql you could simply write something like:
DECLARE
emp employee%rowtype;
BEGIN
FOR emp IN SELECT * FROM employee LOOP
IF emp.active THEN
RAISE INFO 'Active: %', emp.employee_id
END IF;
END LOOP;
END
In the above, the plpgsql language handler deals with opening, binding, fetching and closing itself (more on declarations, and control structures).
With PostgreSQL from 9.0, you can simply drop into executing plpgsql using a "DO" block. For prior versions, you need to create a function and select it. If you're looking for the PostgreSQL equivalent of, for example, iterating through a result with a cursor on SQL Server, that's what it is. Note that iteration etc. are not part of the SQL dialect, only part of plpgsql (or any of the other emebedded languages).
The "DECLARE CURSOR xxx" syntax at the SQL level can be used like this:
DECLARE cur_employees CURSOR FOR SELECT * FROM employee;
FETCH NEXT FROM cur_employees;
// etc..
CLOSE cur_employees;
This can be used to carefully get just part of the query result set. However, it's unusual to use these, since usually your client driver will provide some sort of functionality to do this (e.g. scrollable result sets in JDBC). You can also return cursors from functions similar to Oracle, although again that's a comparatively rare use case.
Generally, one has a DECLARE for the cursor, then an OPEN of the cursor (which materializes the result set), multiple FETCH operations to retrieve the rows from the result set individually, and then one does a CLOSE of the cursor.
You appear to have a DECLARE followed by a CLOSE. Thus your syntax error, as you never did an OPEN.