Parameterizing adhoc scripts - oracle

In SQL server I always had a set of diagnostic scripts and always made sure to declare variables with identifiers so that my other selects and updates would leverage them. I'm having trouble adopting this pattern in Oracle.
I might have 4 or 5 select queries, and then also some updates that I may uncomment once I've verified the results. I want to see the results of the select queries in output.
I am using SQL Developer.
First I tried using a DEFINE block, but it seems this must be paired with BEGIN/END block, and once a query is inside a block, it seems like it becomes cumbersome to view the results. The examples I've seen either involve setting a cursor then iterating over the cursor to print results, or you must print individual values which is even more cumbersome.
So instead I tried using variable's since I can reference them without declare/begin/end, but I am having trouble setting the value of the variable:
variable customerid number;
customerid := 1234;
But I get this error:
Error starting at line : 5 in command - customerid := 1234 Error
report - Unknown Command
I also tried
select t.customerid into :customerid
from customer t
where t.customerid = 1234
and get:
SQL Error: ORA-01006: bind variable does not exist
01006. 00000 - "bind variable does not exist"
My goal is to have my id declarations at the top where I set the values, and be able to run the script and all my adhoc selects appear in output.

You need to set the bind variable in a PL/SQL context, either with an execute syntactic wrapper:
variable customerid number;
exec :customerid := 1234;
or slightly more explicitly:
variable customerid number;
begin
:customerid := 1234;
end;
/
which is (almost) equivalent, but will probably be more convenient if you want to set multiple variables. You can populate the bind variabke from a query too, as you attempted, but that also needs to be in a PL/SQL context:
begin
select t.customerid into :customerid
from customer t
where t.customerid = 1234;
end;
/
Notice the colon before customerid, indicating it is a bind variable, in all of those. You need that when you reference it later, e.g. in a SQL query (which doesn't need to be in a PL/SQL block):
select * from customer where customerid = :customerid;
You can use the same mechanism in your updates later. The exception to using a colon is if you want to just see the value of the variable; you could select :customerid from dual, but there is also the ability to
print customerid
That's even more useful if your variable is a refcursor.
define is a completely different mechanism, for substitution variables rather than bind variables. You don't need to use PL/SQL blocks for this either:
define customerid=1234
select * from customer where customerid = &customerid;
Notice there is no colon this time. And also note that if your variable is a string, you need to enclose it in quotes when you use it:
define name=aaron
select * from users where first_name = '&name';
You can also use the result of a query to populate a substitution variable, using the new_value syntax.

Related

Why pl sql assignment operator throws error while reading from sql query?

set serveroutput on;
declare
v_emp_first_name US_EMPLOYEES.FIRST_NAME%TYPE;
BEGIN
select us_employees.first_name into v_emp_first_name from us_employees where email = 'jbutt#gmail.com';
dbms_output.put_line('v_emp_first_name --> ' || v_emp_first_name);
v_emp_first_name := select first_name from us_employees where email = 'kris#gmail.com';
dbms_output.put_line('v_emp_first_name --> ' || v_emp_first_name);
END;
When I compile above code the below statement throws error
v_emp_first_name := select first_name from us_employees where email = 'kris#gmail.com';
Is it not possible to read a column value via a sql query and map that value using assignment operator ?
If i have the below code alone then it compile and works fine
select us_employees.first_name into v_emp_first_name from us_employees where email = 'jbutt#gmail.com';
The short answer is NO. You can't assign the output of a scalar query to a variable. The proper syntax for your "assignment" is the one you are already aware of.
I am sure that you will then ask WHY. Why did Oracle choose that "weird" syntax for assignment, and not the simpler one you tried?
The answer is that in more general cases a select statement may return multiple columns, not just one; and the values from multiple columns can be "assigned" to multiple variables (local to the PL/SQL block) simultaneously. Which, by the way, is the more common usage - people extract one "record" at a time, rather than a single value. So, how would you re-write the "select into" operation as an "assignment" (or multiple "assignments")? There is no natural way to do that.
You may ask why Oracle doesn't allow "your" assignment syntax, in the case of a single column selected, in addition to the select into syntax (which is needed for multi-column rows anyway). The answer is that would be wasteful. We already have a syntax - that we need for more general cases anyway; we don't need one more.
You might say that we could put all the receiving local variables into a record type, and do a single assignment (to a record) even for general "rows" returned by a select. Alas, SQL statements return rows, not records; rows are a SQL concept, and specifically they are not a data type. Perhaps Oracle could do further development along those lines (to add functionality that doesn't exist today), but why bother - they already have a perfectly fine syntax for what you need, and you already know what that syntax is - without needing to define a record type to hold all your local variables, then define a "record type" for rows coming from a SQL select statement, then .....
You have issue with this code:
v_emp_first_name := select first_name from us_employees where email = 'kris#gmail.com';
You can not use the assignment operator against the query as you have used.
Replace this assignment := with INTO as follows:
select first_name INTO v_emp_first_name from us_employees where email = 'kris#gmail.com';

I'm trying to create a procedure in Pl/Sql and I'm getting this error

https://imgur.com/a/ll59wjx - Picture
I'm trying to calculate the current product stock.
I have product_reception table in which I can calculate my stock.
And sales (vanzari) table.
Posting code as an image is usually a bad idea.
Anyway: quite a few objections:
don't enclose procedure (or table, column, ...) name into double quotes
name parameters so that their name is different from column names, for example: not cod_pds in number but par_cod_pds in number
declare variable in the declaration section, which is between is and begin. Don't use var (key)word. It is a good idea to name them so that the name reflects the fact that these are local variables, such as l_stoc_pds number
don't use exec within a PL/SQL procedure, especially not to run a select statement. exec is used in SQL*Plus to run a PL/SQL procedure, such as exec calculstoclazi
don't select into a variable preceded by a colon, but simply name the variable
those two select statements are exactly the same; I have no idea what you meant to do by doing that. Besides, you preceded cod_pds with stoc_pds which is a variable name (so that's totally wrong); if a column name is to be preceded by something, that's table name (or its alias)
Therefore, code that might look like something valid is this; obviously, the result will be 0 (zero). As I told you, those two selects are exactly the same.
create or replace procedure calculstoclazi
(par_cod_pds in number,
par_rezultat out number
)
is
l_stocs_pds number;
l_total_vanzare number;
begin
select sum(cantitate)
into l_stoc_pds
from receptie_marfa
where cod_pds = par_cod_pds;
select sum(cantitate)
into l_total_vanzare
from receptie_marfa
where cod_pds = par_cod_pds;
par_rezultat := l_stoc_pds - l_total_vanzare;
end;

PL/SQL : Can we have same name for variable and column

In the tutorial i learned that we cannot have same name of variable and column
Here is the link
so i tried this
set SERVEROUTPUT ON;
declare
n1 number;
name varchar(10);
begin
null;
DBMS_OUTPUT.PUT_LINE('sparsh' || TO_CHAR(45));
select name into name from Employee;
DBMS_OUTPUT.PUT_LINE(name);
END;
/
Here i have name column in the table and with the same name i declare the variable.
As per the tutorials it should give some error. But it is working fine
Could you please help me in order to clarify.
So can we have variable with same name of column?
The tutorial is slightly wrong. It is possible to have variables with the same name in SQL and PL/SQL but it is almost certainly a bad idea to do so.
Using variables with the same name will lead to confusing scope issues. The PL/SQL block will correctly use the PL/SQL name for the INTO clause, but it would also use it other places you might not expect. For example, if you tried to use it in the WHERE clause the SQL name would be used instead.
drop table employee;
create table employee(id number, name varchar2(100));
insert into employee values (1, 'Alice');
declare
name varchar(10) := 'Bob';
begin
select name into name from Employee where name = name;
dbms_output.put_line(name);
END;
/
OUTPUT:
Alice
This is the real reason why it's a good practice to name local variables V_ for "variable", and P_ for "parameter". It's not because of some stupid Systems Hungarian notation rules. (So don't also start naming your variables _IN_, _NUM_, etc!) It's because in practice you want to use the same names in PL/SQL and SQL but you don't want to get them confused.
declare
name varchar(10) := 'Bob';
begin
select name into name from Employee where **id= id**;
dbms_output.put_line(name);
END;
/
I am using the same example given by Jon.
See the condition where id = id.
If you use a variable with a name same as of the column name.It would not throw any error but it would certainly astonish you with a huge and unexpectedly large dataset.
In Conditional predicates column names get prioritized over variable names.
Hence in this case id = id both would be considered as table columns and condition will be evaluated into TRUE for all rows.
There is no such rule while choosing the name of the variables.but it's better to keep the standards.
Should this be something SQL tools like Toad should be picking up on? e.g. if you try to run a query like this it would fail with a message to say something like 'Declared variable name should not be the same as Column name in query'? Or should it be a SQL error thrown? I can't think of any situation where you would want to do this and want the outcome so surely it shouldn't be possible to do it?

ORA-0675:package or function ORG_SPGETTYPE is in an invalid state

PROCEDURE ORG_spGetType
(
v_TypeId IN NUMBER DEFAULT NULL
)
AS
BEGIN
SELECT *
FROM ORG_Type
WHERE TypeId = v_TypeId ;
END;
While Running above proceedure in oracle10g usinq eclipse platform sql editor getting error like "ORA-0675:package or function ORG_SPGETTYPE is in an invalid state"
That's not much of a surprise; that procedure is invalid. When compiling a procedure or any other PL/SQL block you should check whether it's compiled correctly.
If you're compiling on the command line, i.e. in SQL*Plus you can use the SHOW command and use the ERRORS variable, which:
displays the line and column number of the error (LINE/COL) as well as the error itself (ERROR).
After you've compiled the procedure type the following:
show errors
Alternatively, you can use the USER_ERRORS system view which will show you a list of all errors, which the schema you're in can see.
select *
from user_errors
where name = 'ORG_SPGETTYPE'
The actual reason for your error is that you cannot simply SELECT in PL/SQL. If you do you're not giving PL/SQL the ability to use the results of your SELECT statement in any way and so it won't allow you to do so. If you're selecting something you need to do something with it; what that something is is up to you.
There are numerous ways of doing this but let's say the table ORG_TYPE is unique on the column TYPEID and you want to return one column as an OUT parameter. Your procedure would then look like this:
create or replace procedure org_spgettype (
P_typeid in org_type.type_id%type
, P_some_column out org_type.some_column%type
) is
begin
select some_column into P_some_column
from org_type
where typeid = P_typeid;
end;
/
show errors
Please note a number of things:
There doesn't seem to be any need for the DEFAULT NULL if this is your primary key; it can't be NULL so you don't want to allow this possibility.
I've declared your parameters as the type of the column; this enables you to change the column without having to recode everything.
There is so much more to explain about all of this (exceptions for a start) so I would highly recommend taking some basic tutorials first or asking a colleague/friend for help.
You would have a 'compiled with warnings' message when creating the procedure. You can query the user_errors view to see what problems are reported for your peocedure. You will see something like 'PLS-00428: an INTO clause is expected in this SELECT statement', because you are not selecting into something.
The documentation shows how to do that. You need to declare variables to select into. In this case you could declare a rowtype variable:
CREATE OR REPLACE PROCEDURE ORG_spGetType (v_TypeId IN NUMBER DEFAULT NULL) AS
l_org_type org_type%rowtype;
BEGIN
SELECT *
INTO l_org_type
FROM ORG_Type
WHERE TypeId = v_TypeId ;
-- do something with l_org_type
END;
/
Note that this can get a no_data_found exception if there are no matching rows, or too_many_rows if there are multiple matches for the passed ID.
But it isn't clear what you're planning to do with the retrieved data. This currently does nothing at all with it, it's just selected and then forgotten. The name of the procedure suggests you want to return all or part of the data from the table to the caller. If it's only one field value then this should probably be a function rather than a procedure. Or you could add out parameters to put the values into (as Ben shows), or return a refcursor. Depends what you need.
The default null, however, maybe suggests you sometimes expect more than one result, maybe the whole table if no value is passed - though your where clause won't find anything if v_typeid is null.

Using variables in Oracle SQL Developer 3.2

I am extremely new to SQL, and manage to extract from some other queries we use the following syntax:
--VARIABLES
undefine PF_PROD --product;
undefine PF_PSG --shop;
--QUERY
SELECT *
FROM ET1250
WHERE PRODUCT=&&PF_PROD
AND PRICE_SHOP_GROUP=&&PF_PSG
ORDER BY PERIOD_YEAR desc,PERIOD_WEEK desc;
This works fine as long as I run the undefine statements first, is there a way to make the query always ask for these variables without me having to undefine them first?
Use a single &. This is covered briefly in the SQL Developer documentation:
For substitution variables, the syntax &&variable assigns a permanent
variable value, and the syntax &variable assigns a temporary (not
stored) variable value.
... and in more detail in the SQL*Plus documentation, which is largely relevant for both clients.
Note that if you define or accept a variable then it won't be prompted for even with a single ampersand, but that doesn't seem to be relevant to you at the moment.
There are two types of variable in SQL-plus: substitution and bind.
Substitution variables can replace SQL*Plus command options or other hard-coded text:
define a = 1;
select &a from dual;
undefine a;
Bind variables store data values for SQL and PL/SQL statements executed in the RDBMS; they can hold single values or complete result setsb:
var x number;
exec :x := 10;
select :x from dual;
exec select count(*) into :x from from dual;
exec print x;
SQL Developer support substitution variables, but when you execute query with bind :var syntax you are prompted for binding (in dialog box).
Reference:
http://www.oracle.com/technetwork/testcontent/sub-var-087723.html SQL*Plus Substitution Variables, Christopher Jones, 2004
https://stackoverflow.com/a/22171706/173149

Resources