Using variables in Oracle SQL query - sql

I need use variable in select statement, but I don't know what I doing wrong.
If I run the test script bellow, it's works fine:
DECLARE
SalesOrderId VARCHAR(10);
BEGIN
SalesOrderId := '138296584';
dbms_output.put_line(SalesOrderId);
END;
But, if I put a select query inside Begin-End block, don't work. Here the code:
DECLARE
SalesOrderId VARCHAR(10);
BEGIN
SalesOrderId := '138296584';
dbms_output.put_line(SalesOrderId);
SELECT * FROM tblOrders tbl WHERE tbl.SalesOrderId = SalesOrderId;
END;
And throws the error:
[Error] Execution (8: 5): ORA-06550: line 8, column 5: PLS-00428: an INTO clause is expected in this SELECT statement
What I doing wrong?
Thanks.

There error is clear, you need to store the output somewhere (make sense) , so use the INTO :
SELECT tbl.SalesOrderId,tbl.column1
INTO varSalesOrderId,varColumn1
FROM tblOrders tbl
WHERE tbl.SalesOrderId = SalesOrderId;

Related

Subquery in SQL with LOOP

I am getting an error when trying to run a select statement in a PLSQL loop. How can I get it to work?
DECLARE
v_gsp_cnt number := 0;
BEGIN
WHILE v_gsp_cnt > (select max(eachesrem) from salesplan)
LOOP
insert into salesplanexp (select SPNUM,ORDNUM,DMDTYPE,ORDSTATUS,ITEM,LOC,ITEMDESCR,FCST,ORDTYPE,DELSERVLVL,SHIPMETHOD,CARRIER,EACHES,SHIPPEDEACHES,EACHESREM,WEIGHT,VOLUME,STARTSHIPDATE,ENDSHIPDATE,ACTSHIPDATE,STARTDELDATE,ENDDELDATE,ACTDELDATE,ORDCREATEDATE,ORDCONFDATE,BILLCUSTNAME,BILLADD1,BILLADD2,BILLCITY,BILLSTATE,BILLCOUNTRY,BILLZIP,SHIPCUSTNAME,SHIPADD1,SHIPADD2,SHIPCITY,SHIPSTATE,SHIPCOUNTRY,SHIPZIP,LOCPHONE,LOCEMAIL,ACTITEMCOST,ACTITEMPRICE,ACTITEMMARGIN,ACTSHIPCOST,ACTSHIPPRICE,ACTSHIPMARGIN,ACTTOTCOST,ACTTOTPRICE,ACTTOTMARGIN,BRAND,CHANNEL,EXTORDID,EXTLINEID,SOURCESYS,CREATEDATE,LASTUPDATEDDATE from salesplan);
commit;
select x.new_cnt into v_gsp_cnt from (select v_gsp_cnt+1 from dual) x;
commit;
END LOOP;
END;
The error is
ORA-06550: line 4, column 23:
PLS-00405: subquery not allowed in this context
ORA-06550: line 4, column 5:
PL/SQL: Statement ignored
The error, I believe, is from the select statement. But with the loop, I'm not sure another way to make it run properly
The error is coming from this line:
WHILE v_gsp_cnt > (select max(eachesrem) from salesplan)
the actual error is a bit deceiving, but that's the source (note it says "line 4" .. count from DECLARE).
You can't have a query like this in this place.
try this instead:
select max(eachesrem) into v_max from salesplan;
WHILE v_gsp_cnt > v_max
(and as well mentioned by JNevill: you need to alias the inner "v_gsp_cnt+1" as new_cnt ... ) but that's a different error which will show up after you fix the one above. ;)

Declaring variables and select statement in a procedure

I'm writing a SQL procedure which should use calculated date stored as a local variable in a select statement. I'm using Oracle SQL developer. My code is:
create or replace PROCEDURE
my_procedure
AS
BEGIN
DECLARE
l_max_dt DATE;
BEGIN
SELECT MAX(TRX_DT)
INTO l_max_dt
FROM TABLE
WHERE 1=1;
end;
select * from TABLE where trx_dt = l_max_dt;
end;
This code gives me an error : " Error(14,48): PL/SQL: ORA-00904: "L_MAX_DT": invalid identifier" when select statement is present.
How can I store variables to use them in statements?
This is how you write a Procedure. Syntax is incorrect. Read about syntax Here
CREATE OR REPLACE PROCEDURE my_procedure
AS
l_max_dt DATE;
v_var TABLE2%ROWTYPE;
BEGIN
SELECT MAX (TRX_DT)
INTO l_max_dt
FROM TABLE1
WHERE 1 = 1;
-- Assuming the query will retrun only 1 row.
SELECT *
INTO v_var
FROM TABLE2
WHERE trx_dt = l_max_dt;
END;
Your issue is one of scope. In your procedure, you have a nested block, in which you declare the l_max_dt variable. Once the code has exited that block, the l_max_dt variable is no longer in scope - i.e. the outer block does not know anything about it.
There is no need to have a nested block in this instance - you can do it all in the same block, like so:
create or replace PROCEDURE my_procedure
AS
l_max_dt DATE;
BEGIN
SELECT MAX(TRX_DT)
INTO l_max_dt
FROM TABLE
WHERE 1=1;
-- commented out as this isn't valid syntax; there is a missing INTO clause
-- select *
-- from TABLE where trx_dt = l_max_dt;
END my_procedure;
However, you could simply do the query in one fell swoop - e.g.:
select *
from your_table
where trx_dt = (select max(trx_dt) from your_table);
A couple of points about your procedure:
In PL/SQL, if you use an implicit cursor (i.e. when you put a select statement directly in the body of the code) you need to have something to put the results into. You could bulk collect the results into an array, or you could ensure that you will receive exactly one row (or code error handling for NO_DATA_FOUND and TOO_MANY_ROWS) into a record or corresponding scalar variables.
You shouldn't use select * in your procedure - instead, you should explicitly state the columns being returned, because someone adding a column to that table could cause your procedure to error. There are exceptions to this "rule", but explicitly stating the columns is a good habit to get into.

Dynamic query in Cursor for loop

I am facing one issue with Dynamic query.I am trying to update one update statement by using dynamic SQL in cursor for loop.
Can you please help me how to execute this...
declare
statement varchar2(1000);
begin
for c1 in(select tenant_id from tenant where tenant_id!=0)
loop
for c2 in ( select alignment_id from customer_alignment where affiliation_id is null and tenant_id=c1.tenant_id)
loop
insert into t3 select 1 from dual;
for c3 in ( select *
from ca_primary_address ca,customer_alignemnt ca where ca.affiliation_id is null
and ca.alignment_id=c2.alignment_id
and ca.customer_id=vw.customer_id
and ca.alignment_id=vw.alignment_id
)
loop
statement :='update customer_alignment set affiliation_id='||vw.affiliation_id||' where customer_alignment_id='||customer_alignment_id||';'
execute immediate('begin '||STATEMENT||' end;');
end loop;
end loop;
dbms_output.put_line('Tenant_id '||c1.tenant_id);
end loop;
end;
Am getting below error msg while executing
ORA-06550: line 8, column 10:
PLS-00402: alias required in SELECT list of cursor to avoid duplicate column names
Please help me on this issue.
Many Many thanks for your help.
Sunitha..
Try the following:
...
statement :='update customer_alignment set affiliation_id='||c3.affiliation_id||' where customer_alignment_id='||c3.customer_alignment_id;
execute immediate(statement);
...
You have to qualify your variables used in the update query string with the cursor variable.

Using variables in Oracle script

There is a complex query which generates a report. The query has several sub queries that generate 3-columns table for different products. Each sub query returns one row. All returned rows then need to be united.
But there is one requirement. If there are no result rows for a sub query we need to include the corresponding product to the final report anyway, but specify that Trades_Count is equal to zero.
I can achieve this using set of variables. The following code will work perfectly in MS SQL Server:
DECLARE #PRODUCT_NAME_1 nvarchar(100);
DECLARE #OFFER_VALID_DATE_1 datetime;
DECLARE #TRADES_COUNT_1 int;
DECLARE #PRODUCT_NAME_2 nvarchar(100);
DECLARE #OFFER_VALID_DATE_2 datetime;
DECLARE #TRADES_COUNT_2 int;
--Product 1
select #PRODUCT_NAME_1 = PRODUCT_NAME, #OFFER_VALID_DATE_1 = MAX(EXPIRY_DATE), #TRADES_COUNT_1 = COUNT(DEAL_NUMBER)
from (
--Data extractions with several joins goes here....
) as TempTable1
GROUP BY PRODUCT_NAME
--Product 2
select #PRODUCT_NAME_2 = PRODUCT_NAME, #OFFER_VALID_DATE_2 = MAX(EXPIRY_DATE), #TRADES_COUNT_2 = COUNT(DEAL_NUMBER)
from (
--Data extractions with several joins goes here....
) as TempTable2
GROUP BY PRODUCT_NAME
SELECT ISNULL(#PRODUCT_NAME_1,'Product 1') AS PRODUCT_NAME, #OFFER_VALID_DATE_1 AS MAX_MATURITY, ISNULL(#TRADES_COUNT_1,0)
UNION
(
SELECT ISNULL(#PRODUCT_NAME_2,'Product 2') AS PRODUCT_NAME, #OFFER_VALID_DATE_2 AS MAX_MATURITY, ISNULL(#TRADES_COUNT_2,0)
)
I think that I haven’t used anything T-SQL specific, but pure ANSI-SQL (I’m not 100% sure though).
So this is not working in Oracle.
First of all it requires having only one DECLARE keyword. Then it forces me using Begin … End execution scope. Then it doesn’t allow me to assign variables like I do (see example above) – I need to use “Select INTO” statement instead. After all calculations are done it doesn’t allow me selecting values from local variables. Heck.
Does anyone know how to make it work in Oracle?
Thanks!
PL/SQL is different than t-sql, I did a change with some comments for you, but definitely look at the links from Andy. This was ran in oracle's free SQL Developer (which also has a "Translation Scratch Handler (tools>Migration>Translation Scratch Handler) that may be of use.
--this creates a refcursor to allow us to simply print the results
var refc refcursor
/
declare --here we declare our variables
product_name_1 varchar2(15) ;
offer_valid_date_1 date ;
trade_count_1 number ;
product_name_2 varchar2(15) ;
offer_valid_date_2 date ;
trade_count_2 number ;
begin
begin --this creates a block so we may handle any exceptions just to this
select PRODUCT_NAME, MAX(EXPIRY_DATE), COUNT(DEAL_NUMBER)
into product_name_1 , offer_valid_date_1 , trade_count_1
--in oracle you select INTO, not var=COL
from (
--Data extractions with several joins goes here....
select
123 PRODUCT_NAME,
sysdate EXPIRY_DATE,
5 DEAL_NUMBER
from dual --this is a 'fake' table to generate some data for testing
) TempTable1 --drop the "as"
GROUP BY PRODUCT_NAME ;
exception --if not data is found, then this error is thrown
--if multiple values are thrown an error will also be thrown (not caught here)
when no_data_found then
product_name_1 := null ; --note, to do a var = , we use "var := value;"
offer_valid_date_1 := null;
trade_count_1 := null;
end ;
begin
select PRODUCT_NAME, MAX(EXPIRY_DATE), COUNT(DEAL_NUMBER)
into product_name_2 , offer_valid_date_2 , trade_count_2
--in oracle you select INTO, not var=COL
from (
--Data extractions with several joins goes here....
select 555 PRODUCT_NAME, sysdate EXPIRY_DATE, 6 DEAL_NUMBER
from dual
) TempTable2 -- drop the "as"
GROUP BY PRODUCT_NAME ;
exception --if not data is found, then this error is thrown
--if multiple values are thrown an error will also be thrown (not caught here)
when no_data_found then
product_name_2 := null ;
offer_valid_date_2 := null;
trade_count_2 := null;
end ;
open :refc for --you cannot just have a select statement, you must "open" a cursor for it
--oracle IsNull is NVL (or NVL2 or you can do a case or decode...)
SELECT nvl(PRODUCT_NAME_1,'Product 1') AS PRODUCT_NAME
, OFFER_VALID_DATE_1 AS MAX_MATURITY
, nvl(TRADE_COUNT_1,0)
FROM DUAL --you also must have a table, DUAL is an oracle table for this tasks
UNION
SELECT nvl(PRODUCT_NAME_2,'Product 2') AS PRODUCT_NAME
, OFFER_VALID_DATE_2 AS MAX_MATURITY
, nvl(TRADE_COUNT_2,0)
FROM DUAL;
end ;
/
--now print the results, if you did this in a proc you would simple have this as an output
print refc;
-------------
PRODUCT_NAME MAX_MATURITY NVL(:B1,0)
-------------------------------------- ----------------------
123 18.FEB.2011 08:43 1
555 18.FEB.2011 08:43 1
Oracle concepts used here:
Dual Table , NVL, Variables, pl/sql Exception
and look at this http://www.dba-oracle.com/t_convent_sql_server_tsql_oracle_plsql.htm
PL/SQL formats procedural blocks differently than T-SQL.
You'll want to use the following structure:
DECLARE
astring varchar2(1000);
anumber number;
BEGIN
my SQL code here...
END;
You don't use the # either in PL/SQL. Just use variables names directly.

Using variables in PLSQL SELECT statement

I have a query that queries on ReportStartDate and ReportEndDate so I thought I would use variables in PLSQL. Not sure what I am missing here, but I get an error:
CLEAR;
DECLARE
varReportStartDate Date := to_date('05/01/2010', 'mm/dd/yyyy');
varReportEndDate Date := to_date('05/31/2010', 'mm/dd/yyyy');
BEGIN
SELECT
'Value TYPE',
1 AS CountType1,
2 AS CountType2,
3 AS CountType3
FROM DUAL;
SELECT COUNT (*)
FROM CDR.MSRS_E_INADVCH
WHERE 1=1
AND ReportStartDate = varReportStartDate
AND ReportEndDate = varReportEndDate
;
END;
/
The Error is:
Error starting at line 2 in command:
Error report:
ORA-06550: line 6, column 5:
PLS-00428: an INTO clause is expected in this SELECT statement
ORA-06550: line 8, column 5:
PLS-00428: an INTO clause is expected in this SELECT statement
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
This happens in Toad as well as in SQL Developer.
What is the proper way of using the variables in my WHERE clause?
You cannot use SQL statements directly in a PL/SQL block ( unless you use EXECUTE IMMEDIATE). The columns will need to be fetched into variables ( which is what PL/SQL is telling you with PLS-00428: an INTO clause is expected in this SELECT statement error). So you'll have to rewrite your statements as below.
SELECT
'Value TYPE',
1 AS CountType1,
2 AS CountType2,
3 AS CountType3
INTO
V_VALUE_TYPE,
V_CountType1,
V_CountType2,
V_CountType3
FROM DUAL;
SELECT COUNT(*)
INTO V_COUNT
FROM CDR.MSRS_E_INADVCH
WHERE 1=1
AND ReportStartDate = varReportStartDate
AND ReportEndDate = varReportEndDate
Be sure to add Exception Handlers, since PL/SQL expects only 1 row to be returned. If the statement returns no rows, you'll hit a NO_DATA_FOUND exception - and if the statement fetches too many rows, you'll hit a TOO_MANY_ROWS exception.
The question you have to answer is what do you want to do with the data that has been selected?
Sathya gave you one approach - declare variables in your PL/SQL block and select the columns INTO those variables. Note that this requires that the SELECT statement returns exactly one row - any more or less rows will throw an error. Another way is to declare collection types using the BULK COLLECT option: http://oracletoday.blogspot.com/2005/11/bulk-collect_15.html
Yet another option is to have the procedure return a cursor. This is useful in the case where the calling code expects to be able to fetch the data that the procedure has selected:
PROCEDURE GET_MY_REPORT( varReportStartDate in date, varReportEndDate in date, cur out sys_refcursor) is
begin
OPEN cur FOR SELECT *
FROM CDR.MSRS_E_INADVCH
WHERE 1=1
AND ReportStartDate = varReportStartDate
AND ReportEndDate = varReportEndDate;
END GET_MY_REPORT;