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?
Related
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;
I have created a stored procedure in Oracle - see below
create or replace PROCEDURE REMOVE_CUSTOMER
(
cus_id IN NUMBER
)
AS
BEGIN
DELETE FROM CUSTOMER WHERE CUSTOMER.CUS_ID = cus_id;
END;
I executed it like below.
DECLARE
CUS_ID NUMBER;
BEGIN
CUS_ID := 192981;
REMOVE_CUSTOMER(CUS_ID => CUS_ID);
END;
It supposes to delete customer 192981 only. However, all customers in the table got deleted. Can anybody tell me what it was wrong with the pl/sql?
The statement within the procedure:
DELETE FROM CUSTOMER WHERE CUSTOMER.CUS_ID = cus_id;
The query parser must identify what cus_id is on the right-hand side. If the table has a column by that name, that's the first choice. This is why everything is deleted; the RHS is interpreted to mean customer.cus_id.
If no such column existed in the table, the second guess would be a variable defined in the procedure. But that is only the second choice, not the first.
Best practice is to use DIFFERENT names for procedure variables, perhaps prefix the column name with p_ (for parameter) or i_ (for input): p_cus_id.
You CAN use the same name for your procedure variable, but then you must fully qualify it in the SQL statement:
where customer.cus_id = remove_customer.cus_id
Actually you don't need to qualify in the left-hand side; this will work:
where cus_id = remove_customer.cus_id
By contrast, what you do in the anonymous block (when you call the procedure) doesn't cause problems. It is still a bad practice to use the column name as the name of the variable declared in the anonymous block, but when you call the stored procedure from the anonymous block, there can be no confusion as to which CUS_ID is the input to the stored procedure; it can't be a column name from a table, and it can't be the variable from the SP (which is "in scope" only in the SP, it is not visible to the caller - the anonymous block).
I am very new to oracle's sql developer (since we've studied mysql) as well as in programming. I've searched in this website the answer to my question but I really can't understand the solutions provided.
What I want is to return the ID generated after inserting an object from java into the database. I'm using mybatis and oracle 10g database. I've already created the table and its columns.
Here's my code for the mapper
<insert id="addUser" parameterType="User" statementType="CALLABLE">
{ CALL addUserSP(
#{user.surname, javaType=String, jdbcType=VARCHAR, mode=IN},
#{user.firstName, javaType=String, jdbcType=VARCHAR, mode=IN},
#{userId, javaType=Integer, jdbcType=NUMBER, mode=OUT}
)}
</insert>
Here's my stored procedure (and I've already create a package named 'CREATEUSER')
PROCEDURE ADDUSERSP
( surname IN VARCHAR2,
firstName IN VARCHAR2,
userId OUT NUMBER
) AS
BEGIN
INSERT INTO users("surname", "first_name")
VALUES (surname, firstName);
RETURNING user_id INTO userId;
END ADDUSERSP;
According to what I've found here, it seems that I need to create a trigger(?) and sequence(?) to make the user_id auto increment whenever I add new data into the table. However, I have no idea how to do it.
Here are my questions:
Is my stored procedure right? Are the codes incomplete? I mean, I have not declared the package in the mapper and I've seen that it is needed (?), something like this { CALL [CreateUser].[addUserSP]( blah blah.... Should I write a sequence and trigger or there is an easy way to make the primary key user_id to be auto incremented? Kindly also check the syntax. I have a lot of problems in syntax.
Thank you so much!
To emulate MySQL AUTO_INCREMENT in Oracle, that pattern (as you found) does use a SEQUENCE object and a BEFORE INSERT trigger.
As a demonstration, something like this for the sequence object:
CREATE SEQUENCE myseq START WITH 1 INCREMENT BY 1 ;
And something like this for the before insert trigger:
CREATE TRIGGER users_bi
BEFORE INSERT ON users
FOR EACH ROW
BEGIN
IF :NEW.id IS NULL THEN
SELECT myseq.NEXTVAL INTO :NEW.id FROM DUAL;
END IF;
END
As far as the procedure, I'm not a big fan of extra PL/SQL blocks that wrap a SQL INSERT statement.
It looks like you have an extra semicolon, before RETURNING. That clause is part of the INSERT statement, not a separate statement.
One big gotcha to be aware of is that SQL statements within a PL/SQL block can reference both columns and PL/SQL variables. When variables have the same names as columns, you will likely encounter behavior you didn't expect.
Typically PL/SQL author use a naming convention for variables that reduces the likelihood of name collisions. We frequently see variables with names like v_surname. (Personally, I use a slightly different convention, but the variable names "look like" variable names, not column references. And I don't name columns following the pattern I use for variables.)
The double quotes around the identifiers are acceptable, but this does make the identifiers case sensitive. When identifiers aren't enclosed in double quotes, Oracle treats them as if they were UPPER CASE. Just make sure that your table was defined with lower case column names.
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.
declare
dno number(4);
dname varchar2(5);
ddate date;
dbasic number(10);
djob varchar2(15);
dcomm number(5);
dept number(5);
dmgr number(5);
begin
select empno,ename,hiredate,sal,job1,comm,deptno,mgr
into dno,dname,ddate,dbasic,djob,dcomm,dept,dmgr
from emp
where empno=&userno;
if sql%rowcount>0
then
insert into newempl
values(dno,dname,djob,dmgr,ddate,dbasic,dcomm,dept);
dbms_output.put_line('records inserted into it');
dbms_output.put_line(dno||' '||dname||' '||ddate||' '||dbasic);
end if;
end;
Error report:
ORA-01858: a non-numeric character was found where a numeric was expected
ORA-06512: at line 19
01858. 00000 - "a non-numeric character was found where a numeric was expected"
*Cause: The input data to be converted using a date format model was
incorrect. The input data did not contain a number where a number was
required by the format model.
*Action: Fix the input data or the date format model to make sure the
elements match in number and type. Then retry the operation.
I do not understand what the error is.
From the error message it looks like you're inserting values into the wrong columns. Without seeing your table structure (from describe newmpl for example) this is a bit of a guess, but this statement:
insert into newempl
values(dno,dname,djob,dmgr,ddate,dbasic,dcomm,dept);
... is assuming that the columns in the newempl table are in a certain order, which may not be (and appears to not be) the case. More specifically here, I think it's complaining about hiredate, as you're implicitly putting the djob value in that column - assuming the new table looks like emp - and the djob value can't be converted into a date.
Update based on comment: from how you said you created the table, this is equivalent to:
insert into newempl(dno, dname, ddate, dbasic, djob, dcomm, dept, dmgr)
values(dno,dname,djob,dmgr,ddate,dbasic,dcomm,dept);
... so as you can see when it's laid out like that the columns are not aligned, and you are indeed trying to put your djob value into the ddate column, which won't work.
It is always safer to explicitly specify the columns, both to prevent problems with different ordering in different environments (though that shouldn't really happen with controlled code) and to prevent this breaking if a new column is added. Something like:
insert into newempl(empno,ename,jon1,mgr,hiredate,sal,comm,deptno)
values(dno,dname,djob,dmgr,ddate,dbasic,dcomm,dept);
As an aside, when declaring your local variables you could specify them based on the table, for example dno emp.empno%TYPE. And as another aside based on your comment, I'd recommend giving local variables different names to the table columns to avoid confusion.
As a_horse_with_no_name said, this can be done with a simple SQL insert, and even within a PL/SQL block it doesn't need separate select and insert statements; you could just do:
insert into newempl(empno,ename,jon1,mgr,hiredate,sal,comm,deptno)
select empno,ename,jon1,mgr,hiredate,sal,comm,deptno
from emp
where empno=&userno;
Unfortunately none of this addresses the requirement that 'the employees who are managers must be inserted into new table', since you aren't doing anything with the mgr column. I don't think it would be constructive to do that part of the task for you at this point though, and I'm not sure where &userno fits in to that.