简体   繁体   中英

Storing a variable in Oracle PL SQL

I hope you can help - I'm strying to assign a date to a variable, and then call that variable in my select query. The code I'm posting is only part of what I'm strying to do, I will be calling that variable more than once. I've tried to google for help, but I'm stuck on using the Select Into statement, as I've got so many selects already.

DECLARE 
    CurrMonth DATE := '27 may 2012'; -- Enter 27th of current month  

BEGIN

SELECT 
    a.policynumber
    ,a.cifnumber
    ,a.phid
    ,a.policystartdate
    ,b.sistartdate
    ,c.dateofbirth
    ,'28/02/2013' AS TaxYearEnd
    --Complete tax year end in the SELECT statement (once for tax year end and once for the age at tax year end)
    ,round ((months_between('28 feb 2013',c.dateofbirth)/12),8) AS AgeAtTaxYearEnd 
    ,b.sifrequency AS CurrSIFrequ
    ,b.sivalue AS CurrentSIValue
    ,b.simode AS CurrentSIMode
    ,d.anniversarydate AS CurrentAnnDate
    ,d.anniversaryvalue AS CurrentAnnValue
    ,b.ruleeffectivedate
    ,b.sistatus AS CurrentSIStatus
    ,b.paymentbranchcode AS CurrSIBranchCode
    ,b.transferaccounttype AS CurrSIAccountType
    ,b.transferaccountnumber AS CurrSIAccountNo
    ,SUM(k.unitbalance) AS unitbalance
    ,a.latestrule
FROM fcislob.policytbl a
    ,fcislob.policysitbl b
    ,fcislob.unitholderdetailtbl c
    ,fcislob.policyanniversaryvaluetbl d
    ,fcislob.unitholderfundtbl k
WHERE a.policynumber = b.policynumber
    AND a.policynumber = d.policynumber
    AND b.policynumber = d.policynumber
    AND a.phid = c.unitholderid
    AND a.phid = k.unitholderid
    AND c.unitholderid = k.unitholderid
    AND a.ruleeffectivedate = b.ruleeffectivedate
    AND a.ruleeffectivedate = d.ruleeffectivedate
    AND b.ruleeffectivedate = d.ruleeffectivedate
    AND a.latestrule <> 0
    AND c.authrejectstatus = 'A'        
    AND a.phid LIKE 'AGLA%'
    AND b.sistatus <> 'C'
    AND k.unitbalance >0     
    AND b.transactiontype = '64'
    AND b.sistartdate <= CurrMonth                                              
    AND b.sifrequency = 'M'

GROUP BY a.policynumber, a.cifnumber, a.phid, a.policystartdate, b.sistartdate , c.dateofbirth,b.sifrequency, b.sivalue, b.simode, d.anniversarydate, d.anniversaryvalue, b.ruleeffectivedate,
    b.sistatus, b.paymentbranchcode, b.transferaccounttype, b.transferaccountnumber, b.policynumber, a.latestrule;
    END;
  1. You have a group by clause so you need to group by all collumns which aren't aggregated.
  2. Are you sure you have only one record in the result ?
  3. As @TonyAndrews said, you need the into clause. You need to declare a variable for every collumn and insert into it,

ie:

DECLARE
  v_policynumber fcislob.policytbl.policynumber%TYPE;
  v_cifnumber    fcislob.policytbl.cifnumber%TYPE;
  v_phid         fcislob.policytbl.phid%TYPE;
  -- and so on ...
  v_sum          number;
BEGIN
    SELECT SUM(k.unitbalance), a.policynumber, a.cifnumber, a.phid -- and so on ...
      INTO v_sum, v_policynumber, v_cifnumber, v_phid -- and so on ...
      FROM fcislob.policytbl a -- and so on ...
  GROUP BY a.policynumber, a.cifnumber, a.phid -- and so on ...
END;
  1. The way you deal with dates is not "healthy", IMO it's better to use to_date and not realy on NLS parameters

If you are only using PL/SQL to be able persist the date value between several plain select statements, then it will complicate things a lot - switching to select into isn't straightforward if you just want to display the results of the query, particularly if there are multiple rows.

Since you mention you have many selects, I'm guessing you have them in a script file ( example.sql ) and are running them through SQL*Plus, like sqlplus user/password @example . If so you can keep your plain SQL statements and use positional parameters , substitution variables , or bind variables to track the date.

First option is if you want to pass the date on the command line, like sqlplus user/password @example 27-May-2012 :

set verify off
select 'Supplied date is ' || to_date('&1', 'DD-Mon-RRRR') from dual;

This uses the first positional parameter, which is referenced as &1 , and converts it to a date as needed in the query. The passed date has to be in the format expected by the to_date function, which in this case I've made DD-Mon-RRRR. Note that you have to enclose the variable in single quotes, otherwise (unless it's a number) Oracle will try to interpret it as a column name rather than a value. (The set verify off suppresses messages SQL*Plus shows by default whenever a substitution variable is used).

You can reference &1 as many times as you want in your script, but you may find it easer to redefine it with a meaningful name - particularly useful when you have multiple positional parameters - and then use that name in your queries.

define supplied_date = &1
select 'Supplied date is ' || to_date('&supplied_date', 'DD-Mon-RRRR') from dual;

If you don't want to pass the date from the command line, you can use a fixed value instead. I'm using a different default date format here, which allows me to use the date literal syntax or the to_date function.

define curr_date = '2012-05-31';
select 'Today is ' || date '&curr_date' from dual;
select 'Today is ' || to_date('&curr_date', 'YYYY-MM-DD') from dual;

You may want to derive the date value, using the result of one query in a later one. You can use the column ... new_value SQL*Plus command to do that; this defines a substitution variable curr_date with the string value from the today column (alias) from any future query, and you can then use it in the same way:

column today new_value curr_date
select to_char(sysdate, 'DD-Mon-YYYY') as today from dual;
select 'Today is ' || to_date('&curr_date', 'DD-Mon-YYYY') from dual;

You can also use bind variables, which you define with the var[iable] command, and set with exec :

var curr_date varchar2(10);
exec :curr_date := '2012-05-31';
select 'Today is ' || to_date(:curr_date, 'YYYY-MM-DD') from dual;

( exec is actually a wrapper around an anonymous PL/SQL block, so it means begin :curr_date := '2012-05-31'; end; , but you only really see that if there's an error). Note that it knows the bind variable is a string, so you don't enclose this in single quotes.

You can mix and match, so if you passed a date on the command line you could assign it to a bind variable with exec :supplied_date := '&1' ; or to use current date exec :curr_date := to_char(sysdate, 'YYYY-MM-DD') .

Many combinations possible, so you'll need to pick what suits what you're trying to do, and which you find simplest. Most, if not all, of these should work in SQL Developer too, but not sure about other clients.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM