Skip to Main Content
  • Questions
  • Store a query result in a variable and use in another query

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, J.

Asked: August 15, 2017 - 3:03 pm UTC

Last updated: February 18, 2019 - 1:17 pm UTC

Version: 3.2.20.10

Viewed 100K+ times! This question is

You Asked

I'm trying to store the result of a query in variable and then use the value in another query. The simplified script below works if I select all and hit F5. However, the result goes to the script output screen. If I select all and run statement to get a query result (which I want to export the data), the value from the variable is not passed through.

VARIABLE v_name number;
BEGIN 
  SELECT count(*) 
      INTO :v_name 
    FROM table;
END;
/

SELECT ID,
:v_name
FROM table


Thanks.

and Chris said...

So I'm guessing you're using SQL Developer?

If you want to use "run statement", you have to pass the bind value at run time. So you need to note it down and pass it yourself.

Alternatively, you could run the whole thing as a script and use spool to send the output to a file:

create table t as 
  select rownum id from dual
  connect by level <= 10;
VARIABLE v_name number;
BEGIN 
  SELECT count(*) 
      INTO :v_name 
    FROM T;
END;
/

spool out.log
SELECT ID, :v_name
FROM   T;
spool off


Out.log will hold the results of your query.

Of course, the real question here is:

Why do you need two statements?

In almost all situations you can combine them into one query. Either in a scalar subquery or by joining. For example, here you could do:

SELECT ID, (SELECT count(*) FROM T) ct
FROM   T;

ID  CT  
1   10  
2   10  
3   10  
4   10  
5   10  
6   10  
7   10  
8   10  
9   10  
10  10 


Or, even better, if you just want the count you don't even need a second query. Use count(*) over () and you'll get the total:

SELECT ID, count(*) over () ct
FROM   T;

ID  CT  
1   10  
2   10  
3   10  
4   10  
5   10  
6   10  
7   10  
8   10  
9   10  
10  10 

Rating

  (4 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

J blanken, August 15, 2017 - 4:43 pm UTC

Thanks, Chris.

Spool is almost working the way I need it to. However, it returns the query results, the variable name, and the content of the variable. How can I only get it to return the query result?

Example Result:
[Query]
[Query result]

[variable name]
[variable value]

Also, I don't believe that I can do this one query since I will be using the variable in a couple of different queries.
Chris Saxon
August 16, 2017 - 1:58 pm UTC

Try:

set term off
set feed off

procedure

Noe, February 16, 2019 - 3:43 am UTC

var :=(SELECT count(*) FROM CUENTA WHERE ID_CUENTA = ORIGEN
AND ID_CUENTA = DESTINO and
ACTIVA = 'SI' and saldo > 0 );


its correcly... tom
-------------------------------------------all procedure
CREATE OR REPLACE PROCEDURE TRANSFERENCIA (MONTO IN NUMBER(20,2), ORIGEN IN NUMBER, DESTINO IN NUMBER) IS

declare
var:=0;

BEGIN
/*Validar dentro del procedimiento que las cuentas existan, que no estén bloqueadas,
que la cuenta origen tenga fondos y realizar la transferencia como tal.
*/
var :=(SELECT count(*) FROM CUENTA WHERE ID_CUENTA = ORIGEN
AND ID_CUENTA = DESTINO and
ACTIVA = 'SI' and saldo > 0 );
IF var =2 THEN
UPDATE CUENTA SET saldo=saldo - MONTO WHERE ID_CUENTA = ORIGEN;
UPDATE CUENTA SET saldo=saldo + MONTO WHERE ID_CUENTA = DESTINO;
DBMS_OUTPUT.put_line('existen cuentas');

END IF;
end;

Connor McDonald
February 18, 2019 - 1:51 am UTC

Maybe just a direct update?

begin
  UPDATE CUENTA 
  SET saldo = saldo + 
                case when ID_CUENTA = ORIGEN then -MONTO else DESTINO end
  WHERE ID_CUENTA in (ORIGEN,DESTINO)
  and ACTIVA = 'SI' 
  and saldo > 0;

  if sql%rowcount != 2 then
    raise_application_error(-20000,'No obtuve los dos registros que se esperaban.');
  end if;
end;


grim fandango

Racer I., February 18, 2019 - 8:01 am UTC

Hi,

Sorting the updates so the smaller id_cuenta gets updated first may help preventing deadlocks in multi-user environments.
Don't kow if this can be controlled in single-statement updates though.

regards,
Chris Saxon
February 18, 2019 - 1:16 pm UTC

If you're worried about deadlocks, you should select-for-update all the rows you'll be updating at the start to avoid this problem.

compact

Racer I., February 18, 2019 - 8:06 am UTC

Hi,

Is this var:= (SELECT)-assignment legal in PL/SQL? Maybe an improvment in 19c or something? Also not specifying a type for var?

regards,
Chris Saxon
February 18, 2019 - 1:17 pm UTC

Nope:
declare
  v int;
begin
  v := ( select count(*) from dual );
end;
/

ORA-06550: line 4, column 10:
PLS-00103: Encountered the symbol "SELECT" when expecting one of the following:

More to Explore

Analytics

Analytic SQL got you confused? Check out Connor McDonald's complete video course.