I used to do Oracle development many many years ago. I have spent most of the past 15 years doing mainly SQL Server, and where I have done Oracle work, been insulated from the workings by Web services etc.
My question seems to have been asked on the web a few times, but it seems difficult somehow to communicate - at least judging by the answers. I very much appreciate that tools and functionality differ, know I have to learn new things, but this is so simple, yet seems so hard to do.
I am looking to do some ad-hoc queries on the database. At the moment we are using SQL Navigator - I am open to using other tools...
In SQL Server Management Studio, if you open a query window, type a bit of SQL that retuns a value or a set, you get a nice display of the rows or values in a results window.
I've gathered that with Oracle PL/SQL things are a bit different, worked out that I need to return a cursor - but how do I get a tool to display the results?
I started simple:
declare
my_id number := 356655;
cursor c1 is select my_id from dual;
begin
open c1;
end;
This runs fine - but how do I see the results? Are there any tools that deal with this as 'nicely' as SSMS? I am used to being able to do a lot of this, including stuff like
(perhaps not exactly the right syntax? but you get the idea...)
declare
my_id number := 356655;
cursor c1 is select name from my_table where id = my_id;
begin
open c1;
And having the results displayed to me as text/grid. Ideally that there is a nice solution. Some spiffy new tool, maybe?
With SQL Developer or SQL*Plus you can use a bind variable declared before the PL/SQL block:
variable rc refcursor;
declare
my_id number := 356655;
begin
open :rc for select my_id from dual;
end;
/
print rc
RC
-------------------------------
356655
You can also use a bind variable within the query, which can be useful:
variable my_id number;
variable rc refcursor;
execute :my_id := 356655;
begin
open :rc for select :my_id from dual;
end;
/
print rc
The variable and print commands are covered in the SQL*Plus documentation, which largely applies to SQL Developer as well - that has its own documentation, including the commands that are carried over from SQL*Plus.
If you have a function that returns a ref cursor then you can call that in a query, as select func(val) from dual, and then the results can go in a grid; or you can call the function (or procedure) with the same :rc bind variable and print it. But I'm not sure either is helpful if you are only doing ad hoc queries.
On the other hand, using a PL/SQL block for an ad hoc query seems a little heavy-handed, even if your queries are complicated. You'd need a good reason to open a cursor for a select statement from within a block, rather than just running the select directly. (Not sure if that's a SQL Server thing or if you actually have a real need to do this!). If you're just running a query inside the block, you don't need the block, even if you want to keep a bind variable for the values you're using in the query:
variable my_id number;
execute :my_id := 356655;
select :my_id from dual;
:MY_ID
----------
356655
I use Oracle SQL Developer.
Anyway, this should work in any oracle sql client:
If you just want to see your results, you can use
dbms_output.put_line('Foo' || somevar || ' bar');
Before this, run
SET SERVEROUTPUT ON
Check the examples at docs.oracle.com
I would suggest using sql developer available free from the oracle website. There is a button which allows you to run sql as a script which will get back what you want. SSMS doesn't work with pl/sql.
Related
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.
I want to call a stored procedure on every row of a table inside my own stored procedure. In SQL Developer workspace I can simple call it like this:
SELECT my_stored_proc(...)
FROM my_table
However in my stored procedure this doesn't seem to execute:
stmt := 'SELECT my_stored_proc(...) FROM my_table';
EXECUTE IMMEDIATE stmt;
This does work:
DECLARE
l_cursor sys_refcursor;
BEGIN
OPEN l_cursor FOR stmt;
LOOP
FETCH l_cursor INTO ...;
EXIT WHEN l_cursor%NOTFOUND;
my_stored_proc(...);
END LOOP;
...
My question is why is this happening.
The behaviour in your second example is explicitly covered in a prominent note in the documentation:
If dynamic_sql_statement is a SELECT statement, and you omit both into_clause and bulk_collect_into_clause, then execute_immediate_statement never executes. For example, this statement never increments the sequence:
EXECUTE IMMEDIATE 'SELECT S.NEXTVAL FROM DUAL'
Which is essentially what you are doing. Because you don't select the result of your procedure (or, in fact your function) into a variable, the query is not executed, so the function is not called.
As you have multiple rows in your table you can't select into a scalar variable, though you could bulk collect into a collection; or use a cursor as you do in your third example. (Although, if the cursor is being opened with the same statement, you seem to be calling the function twice for each row - once when the query is executed, and then again inside the PL/SQL loop. I'm probably reading too much into your contrived example...)
The answer is simple, yet complicated, and many beginner PLSQL developers seem to not be able to get a grasp on the whole concept of cursors...
Your
SELECT my_stored_proc(...)
FROM my_table
in your SQL Developer executes OK because your SQL Developer opens a cursor for your query, fetches the cursor into your data grid, then closes the cursor.
Your
stmt := 'SELECT my_stored_proc(...) FROM my_table';
EXECUTE IMMEDIATE stmt;
inside a stored procedure fails for the same reason - it opens a cursor for the dynamic SQL, yet it does not have any PLSQL variable to fetch the cursor's results into. If you want to select something, you need to
either open a cursor for it, fetch the data into a PLSQL variable in a loop (and do whatever you want to do with the fetched data), then close the cursor,
or to select/bulk select the query results into a PLSQL variable (and then do whatever you want to do with the fetched data).
... which is what you did in your third code snippet.
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.
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.
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.