This question already has answers here:
Is it possible to return the Primary Key on an Insert as select statement - Oracle?
(2 answers)
Closed 11 months ago.
Is it possible to insert a row into a table from a SELECT statement (as opposed to VALUES syntax) and use the RETURNING clause to retrieve a column value?
Using the SELECT syntax fails with ORA-00933: SQL command not properly ended:
DECLARE
l_id users.id%TYPE;
BEGIN
INSERT INTO users (id, name)
SELECT users_seq.nextval, 'foo'
FROM DUAL
RETURNING id INTO l_id;
END;
/
It works fine with the VALUES syntax of course:
DECLARE
l_id users.id%TYPE;
BEGIN
INSERT INTO users (id, name)
VALUES (users_seq.nextval, 'foo')
RETURNING id INTO l_id;
END;
/
According to the documentation here https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/INSERT.html#GUID-903F8043-0254-4EE9-ACC1-CB8AC0AF3423 (search for single_table_insert) it is not supported in normal SQL, and I believe not in PL/SQL either.
Related
This question already has answers here:
Comma separated values to IN function in oracle
(2 answers)
PL/SQL - Use "List" Variable in Where In Clause
(3 answers)
Closed 5 years ago.
I have the following query
set serveroutput on;
declare store_nbr number(9,0);
Begin
Select trim(NODE_ID) into store_nbr from HOST_STORE_PROFILE
where sysdate between EFCV_DTE and EXPR_DTE and TO_CHAR(NODE_ID) in
('12175','22671','16449');
dbms_output.Put_line(store_nbr);
end;
This works fine and prints a value(store_nbr).
But when I tried to replace the 'in' condition in the select statement with variable declaration, it is not working as desired.
I am doing like this:
declare store_nbr number(9,0);
ca_store_nbr varchar2(4096) := '(12175,22671,25519)';
begin
Select NODE_ID into store_nbr from HOST_STORE_PROFILE
where sysdate between EFCV_DTE and EXPR_DTE and TO_CHAR(NODE_ID) in ||
ca_store_nbr;
dbms_output.Put_line(store_nbr);
end;
I don't get the value into store_nbr.
Whats wrong with the second query.
This needs to be a dynamic sql statement.
make a string out of the whole statement and execute with something like
EXECUTE IMMEDIATE <sql statement>
This question already has answers here:
Error in Oracle stored procedure
(2 answers)
Closed 7 years ago.
I wrote simple stored procedure in oracle. but its shows procedure created with compilation errors.
My code is:
Create PROCEDURE test
(
ID_no varchar
)
AS
BEGIN
SELECT Student.name , Student.dept, from Student
WHERE Student.id=ID_no
END;
/
Please help me to solve this problem .
1) Extra comma -
SELECT Student.name , Student.dept, from
2) semicolon after select is missing -
WHERE Student.id=ID_no
END;
3) If you get the values from query, you should put it to something -
CREATE PROCEDURE test(id_no VARCHAR) AS
s_name student.name%TYPE;
s_dept student.dept%TYPE;
BEGIN
SELECT student.name, student.dept
INTO s_name, s_dept
FROM student
WHERE student.id = id_no;
END;
/
In SQL Server we can use this:
DECLARE #variable INT;
SELECT #variable= mycolumn from myTable;
How can I do the same in Oracle? I'm currently attempting the following:
DECLARE COMPID VARCHAR2(20);
SELECT companyid INTO COMPID from app where appid='90' and rownum=1;
Why this is not working?
SELECT INTO
DECLARE
the_variable NUMBER;
BEGIN
SELECT my_column INTO the_variable FROM my_table;
END;
Make sure that the query only returns a single row:
By default, a SELECT INTO statement must return only one row. Otherwise, PL/SQL raises the predefined exception TOO_MANY_ROWS and the values of the variables in the INTO clause are undefined. Make sure your WHERE clause is specific enough to only match one row
If no rows are returned, PL/SQL raises NO_DATA_FOUND. You can guard against this exception by selecting the result of an aggregate function, such as COUNT(*) or AVG(), where practical. These functions are guaranteed to return a single value, even if no rows match the condition.
A SELECT ... BULK COLLECT INTO statement can return multiple rows. You must set up collection variables to hold the results. You can declare associative arrays or nested tables that grow as needed to hold the entire result set.
The implicit cursor SQL and its attributes %NOTFOUND, %FOUND, %ROWCOUNT, and %ISOPEN provide information about the execution of a SELECT INTO statement.
Not entirely sure what you are after but in PL/SQL you would simply
DECLARE
v_variable INTEGER;
BEGIN
SELECT mycolumn
INTO v_variable
FROM myTable;
END;
Ollie.
One Additional point:
When you are converting from tsql to plsql you have to worry about no_data_found exception
DECLARE
v_var NUMBER;
BEGIN
SELECT clmn INTO v_var FROM tbl;
Exception when no_data_found then v_var := null; --what ever handle the exception.
END;
In tsql if no data found then the variable will be null but no exception
ORA-01422: exact fetch returns more than requested number of rows
if you don't specify the exact record by using where condition, you will get the above exception
DECLARE
ID NUMBER;
BEGIN
select eid into id from employee where salary=26500;
DBMS_OUTPUT.PUT_LINE(ID);
END;
For storing a single row output into a variable from the select into query :
declare v_username varchare(20);
SELECT username into v_username FROM users WHERE user_id = '7';
this will store the value of a single record into the variable v_username.
For storing multiple rows output into a variable from the select into query :
you have to use listagg function. listagg concatenate the resultant rows of a coloumn into a single coloumn and also to differentiate them you can use a special symbol.
use the query as below
SELECT listagg(username || ',' ) within group (order by username) into v_username FROM users;
In SQL Server we can use this:
DECLARE #variable INT;
SELECT #variable= mycolumn from myTable;
How can I do the same in Oracle? I'm currently attempting the following:
DECLARE COMPID VARCHAR2(20);
SELECT companyid INTO COMPID from app where appid='90' and rownum=1;
Why this is not working?
SELECT INTO
DECLARE
the_variable NUMBER;
BEGIN
SELECT my_column INTO the_variable FROM my_table;
END;
Make sure that the query only returns a single row:
By default, a SELECT INTO statement must return only one row. Otherwise, PL/SQL raises the predefined exception TOO_MANY_ROWS and the values of the variables in the INTO clause are undefined. Make sure your WHERE clause is specific enough to only match one row
If no rows are returned, PL/SQL raises NO_DATA_FOUND. You can guard against this exception by selecting the result of an aggregate function, such as COUNT(*) or AVG(), where practical. These functions are guaranteed to return a single value, even if no rows match the condition.
A SELECT ... BULK COLLECT INTO statement can return multiple rows. You must set up collection variables to hold the results. You can declare associative arrays or nested tables that grow as needed to hold the entire result set.
The implicit cursor SQL and its attributes %NOTFOUND, %FOUND, %ROWCOUNT, and %ISOPEN provide information about the execution of a SELECT INTO statement.
Not entirely sure what you are after but in PL/SQL you would simply
DECLARE
v_variable INTEGER;
BEGIN
SELECT mycolumn
INTO v_variable
FROM myTable;
END;
Ollie.
One Additional point:
When you are converting from tsql to plsql you have to worry about no_data_found exception
DECLARE
v_var NUMBER;
BEGIN
SELECT clmn INTO v_var FROM tbl;
Exception when no_data_found then v_var := null; --what ever handle the exception.
END;
In tsql if no data found then the variable will be null but no exception
ORA-01422: exact fetch returns more than requested number of rows
if you don't specify the exact record by using where condition, you will get the above exception
DECLARE
ID NUMBER;
BEGIN
select eid into id from employee where salary=26500;
DBMS_OUTPUT.PUT_LINE(ID);
END;
For storing a single row output into a variable from the select into query :
declare v_username varchare(20);
SELECT username into v_username FROM users WHERE user_id = '7';
this will store the value of a single record into the variable v_username.
For storing multiple rows output into a variable from the select into query :
you have to use listagg function. listagg concatenate the resultant rows of a coloumn into a single coloumn and also to differentiate them you can use a special symbol.
use the query as below
SELECT listagg(username || ',' ) within group (order by username) into v_username FROM users;
In SQL Server, you can declare a table variable (DECLARE #table TABLE), which is produced while the script is run and then removed from memory.
Does Oracle have a similar function? Or am I stuck with CREATE/DROP statements that segment my hard drive?
Yes.
Declare TABLE TYPE variables in a
PL/SQL declare block. Table variables
are also known as index-by table or
array. The table variable contains one
column which must be a scalar or
record datatype plus a primary key of
type BINARY_INTEGER. Syntax:
DECLARE
TYPE type_name IS TABLE OF
(column_type |
variable%TYPE |
table.column%TYPE
[NOT NULL]
INDEX BY BINARY INTEGER;
-- Then to declare a TABLE variable of this type:
variable_name type_name;
-- Assigning values to a TABLE variable:
variable_name(n).field_name :=
'some text'; -- Where 'n' is the
index value
Ref: http://www.iselfschooling.com/syntax/OraclePLSQLSyntax.htm
You might want to also take a look at Global Temporary Tables
The below solution is the closest from SQL Server I can do today.
Objects:
CREATE OR REPLACE TYPE T_NUMBERS IS TABLE OF NUMBER;
CREATE OR REPLACE FUNCTION ACCUMULATE (vNumbers T_NUMBERS)
RETURN T_NUMBERS
AS
vRet T_NUMBERS;
BEGIN
SELECT SUM(COLUMN_VALUE)
BULK COLLECT INTO vRet
FROM TABLE(CAST(vNumbers AS T_NUMBERS));
RETURN vRet;
END;
Queries:
--Query 1: Fixed number list.
SELECT *
FROM TABLE(ACCUMULATE(T_NUMBERS(1, 2, 3, 4, 5)));
--Query 2: Number list from query.
WITH cteNumbers AS
(
SELECT 1 AS COLUMN_VALUE FROM DUAL UNION
SELECT 2 AS COLUMN_VALUE FROM DUAL UNION
SELECT 3 AS COLUMN_VALUE FROM DUAL UNION
SELECT 4 AS COLUMN_VALUE FROM DUAL UNION
SELECT 5 AS COLUMN_VALUE FROM DUAL
)
SELECT *
FROM TABLE(
ACCUMULATE(
(SELECT CAST(COLLECT(COLUMN_VALUE) AS T_NUMBERS)
FROM cteNumbers)
)
);
Yes it does have a type that can hold the result set of a query (if I can guess what TABLE does). From ask Tom: your procedure may look like this:
procedure p( p_state in varchar2, p_cursor in out ref_cursor_type )
is
begin
open p_cursor for select * from table where state = P_STATE;
end;
where p_cursor is like a table type. As has been already answered there are plenty of options for storing result sets in Oracle. Generally Oracle PL/SQL is far more powerful than sqlserver scripts.
the table in variable in oracle not the same as table variables in MS SQLServer.
in oracle it's like regular array in java or c#. but in MS SQLserver it is the same as any table, you can call it logical table.
but if you want something in oracle that does exactly the same as table variable of SQLserver you can use cursor.
regards