简体   繁体   中英

Oracle Last Records from Cursor

I have the following piece of code. For the last line of the cursor I don't need to print the '->' symbol. If you run the query you can see that the fourth record is displayed twice

declare
cursor ch is
  select 1 as n from dual union
  select 2 from dual union 
  select 3 from dual union
  select 4 from dual;
v_ch ch%rowtype;
begin

  open ch;
  loop
    fetch ch into v_ch;
    exit when ch%notfound;
    dbms_output.put_line(LPAD(' ',5)||v_ch.n || '->');

  end loop;
  dbms_output.put_line(LPAD(' ',5)||v_ch.n);
  close ch;
end;

result

 1->
 2->
 3->
 4->
 4

A PL/SQL solution

This will work, just a bit of shifting when to print arrows / newlines:

set serveroutput on
declare
cursor ch is
  select 1 as n from dual union
  select 2 from dual union 
  select 3 from dual union
  select 4 from dual;
v_ch ch%rowtype;
first boolean := true;
begin

  open ch;
  loop
    fetch ch into v_ch;
    exit when ch%notfound;

    -- Append the arrow after all rows except the first and implicitly (because of the
    -- above exit) except the last, too
    if not first then
      dbms_output.put_line('->');
    end if;
    first := false;

    -- Use put here, instead of put_line, such that the arrow will be appended on the
    -- same line as the value on the next loop iteration
    dbms_output.put(LPAD(' ',5)||v_ch.n);
  end loop;

  -- Finally, print a newline character
  dbms_output.put_line('');
  close ch;
end;
/

A SQL solution

Of course, you can generate the arrow also in SQL:

set serveroutput on
declare
cursor ch is
  select n, case 
    when row_number() over (order by n) = 
         count(*) over () then '' else '->' end arrow
  from (
      select 1 as n from dual union
      select 2 from dual union 
      select 3 from dual union
      select 4 from dual
  ) t;
v_ch ch%rowtype;
begin
  open ch;
  loop
    fetch ch into v_ch;
    exit when ch%notfound;
    dbms_output.put_line(LPAD(' ',5)||v_ch.n||v_ch.arrow);
  end loop;
  dbms_output.put_line('');
  close ch;
end;
/

Or even:

select listagg(n, '->' || chr(10)) within group (order by n)
from (
  select 1 as n from dual union
  select 2 from dual union 
  select 3 from dual union
  select 4 from dual
);

This only works if your string won't reach the VARCHAR2 length limit

You could modify the cursor to identify the position of each row; without any ordering information that's a bit clunky:

declare
cursor ch is
  select n, count(*) over () - rownum as c from (
    select 1 as n from dual union
    select 2 from dual union 
    select 3 from dual union
    select 4 from dual
  );
v_ch ch%rowtype;
begin

  open ch;
  loop
    fetch ch into v_ch;
    exit when ch%notfound;
    dbms_output.put_line(LPAD(' ',5)||v_ch.n || case when v_ch.c > 0 then '->' end);
  end loop;
  close ch;
end;
/

     1->
     2->
     3->
     4


PL/SQL procedure successfully completed.

In this example the c column is zero for the final row returned; so the output uses a case expression to only show the arrow when that is greater than zero - ie all except that last row.

With a real query you might be able to just add a column to the current result set using row_number() over (order by <something> desc , which would make the last row #1, and you could base the display logic on that instead. You probably wouldn't need a subquery then either. We can't see your real query though so can only guess how it can best be applied.

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