Usage of cursor in sql select stmt
HI
how can i use cursor in SELECT statement for fetching the multiple records at a time.
thanx.
Hi,
do you mean something like this? - hope I've understood correctlry :-)
Example in Sql*Plus (v 10)
SCOTT>
SCOTT>SELECT A.TABLE_NAME,
2 CURSOR (SELECT B.COLUMN_NAME
3 FROM ALL_TAB_COLUMNS B
4 WHERE B.TABLE_NAME = A.TABLE_NAME
5 ) CURSOR_1
6 FROM ALL_TABLES A
7 WHERE A.TABLE_NAME = 'DUAL'
8 /
TABLE_NAME CURSOR_1
DUAL CURSOR STATEMENT : 2
CURSOR STATEMENT : 2
COLUMN_NAME
DUMMY
1 row selected.
1 row selected.
SCOTT>
SCOTT>
If you want to user this in PL, you need to declare a cursor and fetch the CURSOR_1 column in a ref cursor
this is another example :
procedure Example1 (ppLocId in locations.location_id%type)
is
type rcRefCursor is ref cursor;
cursor cAllInOne is
select l.city,
cursor (select d.department_name,
cursor (select e.last_name
from employees e
where e.department_id = d.department_id
) eName
from departments d
where d.location_id = l.location_id
) dName
from locations l
where location_id = ppLocId;
cDepts rcRefCursor;
cEmployees rcRefCursor;
vCity locations.city%type;
vDepartment departments.department_name%type;
vEmpName employees.last_name%type;
begin
open cAllInOne;
loop
fetch cAllInOne
into vCity,
cDepts;
exit when cAllInOne%notfound;
loop
fetch cDepts
into vDepartment,
cEmployees;
exit when cDepts%notfound;
loop
fetch cEmployees
into vEmpName;
exit when cEmployees%notfound;
dbms_output.put_line ('City : ' || vCity ||
' Dept : ' || vDepartment ||
' Name : ' || vEmpName
end loop;
end loop;
end loop;
close cAllInOne;
end Example1;
bye
fabio
Similar Messages
-
How to simplify this query into simple sql select stmt
Hi,
Please simplify this query
I want to convert this query into single select statement. Is it possible?
If uarserq_choice_ind is not null then
Select ubbwbst_cust_code
From ubbwbst,utrchoi
Where utrchoi_prop_code=ubbwbst_cancel_prod
Else
Select max(utvsrvc_ranking)
From utvsrvc,ubbwbst
Where utvsrvc_code=ubbwbst_cancel_prod
End ifThough i have not tested this statement if mine ...but you can try at your end and let me know whether u got the desired output or not.
Select Decode(uarserq_choice_ind,Null,max_rnking,ubbwbst_cust_code)uarserq_chc
from
(Select max(utvsrvc_ranking)max_rnking,uarserq_choice_ind,ubbwbst_cust_code
From utvsrvc,ubbwbst,utrchoi
Where utvsrvc_code=ubbwbst_cancel_prod
Or utrchoi_prop_code=ubbwbst_cancel_prod
group by uarserq_choice_ind,ubbwbst_cust_code)
Best of Luck.
--Vineet -
What does the usage of CURSOR word mean in an SQL statement?
Hey folks,
Please check out the following query and do please explain me what does the usage of CURSOR keyword in an SQL statement mean.
select deptno,cursor(select ename from emp a where a.deptno=b.deptno) from dept b;
well, the output was like this,
DEPTNO CURSOR(SELECTENAMEFR
10 CURSOR STATEMENT : 2
CURSOR STATEMENT : 2
ENAME
CLARK
KING
20 CURSOR STATEMENT : 2
CURSOR STATEMENT : 2
ENAME
SMITH
JONES
SCOTT
ADAMS
FORD
30 CURSOR STATEMENT : 2
CURSOR STATEMENT : 2
ENAME
ALLEN
WARD
MARTIN
BLAKE
TURNER
JAMES
6 rows selected.
40 CURSOR STATEMENT : 2
CURSOR STATEMENT : 2
no rows selected
Your favour'll be deeply appreciated.
Cheers,
PCZThis returns a non-square result set. Each row of the result is a deptno and then a result set of the enames in that deptno.
This can be useful when you need to send a lot of data to a client application in a single query that would otherwise contain a lot of redundancy. It tends to be a relatively unusual construct (I've only found one situation where it was appropriate in my career) and requires some relatively sophisticated understanding on both the database and client sides.
Justin -
Count (*) for select stmt take more time than execute a that sql stmt
HI
count (*) for select stmt take more time than execute a that sql stmt
executing particular select stmt take 2.47 mins but select stmt is using the /*+parallel*/ (sql optimer) in that sql command for faster execute .
but if i tried to find out total number of rows in that query it takes more time ..
almost 2.30 hrs still running to find count(col)
please help me to get count of row faster.
thanks in advance...797525 wrote:
HI
count (*) for select stmt take more time than execute a that sql stmt
executing particular select stmt take 2.47 mins but select stmt is using the /*+parallel*/ (sql optimer) in that sql command for faster execute .
but if i tried to find out total number of rows in that query it takes more time ..
almost 2.30 hrs still running to find count(col)
please help me to get count of row faster.
thanks in advance...That may be because your client is displaying only the first few records when you are running the "SELECT *". But when you run "COUNT(*)", the whole records has to be counted.
As already mentined please read teh FAQ to post tuning questions. -
What is a good way to check if sql select basd cursor return anything
Hello everyone,
I am trying to find a good way to identify that a SQL select based cursor return nothing.
I know that or we use exception when no data found, or count(*) to check how many rows are returned.
I have a cursor based on quite a long select statement.
Like
CREATE OR REPLACE PROCEDURE aaa (v_input IN NUMBER, v_output OUT VARCHAR2)
CURSOR long_cursor IS
--long select statement(with input variable) ;
BEGIN
Select count(*)
Into v_count
From
-- a long select statment with input again ;
IF v_count > 0 then
For record in long_cursor loop
--Get information from cursor
--other processing for output
End loop;
END IF;
END;Is there any other way than the above ?
I would love to reduce the amount of typing. I know that repetition in code is not good.
Thanks in advance,
Ann
Edited by: Ann586341 on Feb 28, 2013 2:29 PM>
Not sure I understand your point. I am still a new bie here.
>
A flag is just a piece of data. By itself it doesn't prevent anyone from changing the data. And in a multiuser system anything you try to check is based on the COMMITTED data in the system. Two users can be changing two different rows at the same time but neither user will see the other change.
So if you try to count how many rows meet a particular condition you may get a count of 8 but after the other user commits the count might be 7 or 9. So if you use 8 it may not be valid for very long.
>
But the app we use is Oracle Application Express 4.0.
I assume when the data is read, there will be some kind of lock on these rows so other users cannot change it, right ?
Or should I use SELECT for update even I do not update anything here.
>
I can't help you with that one. That would be a question for the application express forum.
Oracle Application Express (APEX)
You don't need to use FOR UPDATE if you don't plan to change the data. But, as explained above, you can't rely on any data you query being the same because another user could be changing it while you are looking at it. -
Reg different kinds of select stmts
Hi All,
Hope all are doing gud,
cud any tell me different kinds of select stmts ????
regards,
abc xyzhi,
SELECT
Basic form
SELECT result [target] FROM source [where] [GROUP BY fields] [ORDER BY order].
Effect
Retrieves an extract and/or a set of data from a database table or view (see Relational database ). SELECT belongs to the OPEN SQL command set.
Each SELECT command consists of a series of clauses specifying different tasks:
The SELECT result clause specifies
whether the result of the selection is a table or a single record,
which columns the result is meant to have and
whether the result is allowed to include identical lines.
The INTO target clause specifies the target area into which the selected data is to be read. If the target area is an internal table, the INTO clause specifies
whether the selected data is to overwrite the contents of the internal table or
whether the selected data is to be appended to the contents and
whether the selected data is to be placed in the internal table all at once or in several packets.
The INTO clause can also follow the FROM clause.
You can omit the INTO clause. The system then makes the data available in the table work area (see TABLES ) dbtab . If the SELECT clause includes a "*", the command is processed like the identical SELECT * INTO dbtab FROM dbtab statement. If the SELECT clause contains a list a1 ... an , the command is executed like SELECT a1 ... an INTO CORRESPONDING FIELDS OF dbtab FROM dbtab .
If the result of the selection is meant to be a table, the data is usually (for further information, see INTO -Klausel ) read line by line within a processing loop introduced by SELECT and concluded by ENDSELECT . For each line read, the processing passes through the loop once. If the result of the selection is meant to be a single record, the closing ENDSELECT is omitted.
The FROM source clause the source (database table or view ) from which the data is to be selected. It also determines
the type of client handling,
the behavior for buffered tables and
the maximum number of lines to be read.
The WHERE where clause specifies the conditions which the result of the selection must satisfy. It thus determines the lines of the result table. Normally - i.e. unless a client field is specified in the WHERE clause - only data of the current client is selected. If you want to select across other clients, the FROM clause must include the addition ... CLIENT SPECIFIED .
The GROUP-BY fields clause combines groups of lines together into single lines. A group is a set of lines which contain the same value for every database field in the GROUP BY clause.
The ORDER-BY order clause stipulates how the lines of the result table are to be ordered.
Each time the SELECT statement is executed, the system field SY-DBCNT contains the number of lines read so far. After ENDSELECT , SY-DBCNT contains the total number of lines read.
The return code value is set as follows:
SY-SUBRC = 0 At least one line was read.
SY_SUBRC = 4 No lines were read.
SY-SUBRC = 8 The search key was not fully qualified.
(nur bei SELECT SINGLE ). The returned single record is any line of the solution set.
Example
Output the passenger list for the Lufthansa flight 0400 on 28.02.1995:
TABLES SBOOK.
SELECT * FROM SBOOK
WHERE
CARRID = 'LH ' AND
CONNID = '0400' AND
FLDATE = '19950228'
ORDER BY PRIMARY KEY.
WRITE: / SBOOK-BOOKID, SBOOK-CUSTOMID, SBOOK-CUSTTYPE,
SBOOK-SMOKER, SBOOK-LUGGWEIGHT, SBOOK-WUNIT,
SBOOK-INVOICE.
ENDSELECT.
Performance
In client/server environments, storing database tables in local buffers (see SAP buffering ) can save considerable amounts of time because the time required to make an access via the network is much more than that needed to access a locally buffered table.
Notes
A SELECT command on a table for which SAP buffering is defined in the ABAP/4 Dictionary is normally satisfied from the SAP buffer by bypassing the database. This does not apply with
- <b>SELECT SINGLE FOR UPDATE
- SELECT DISTINCT in the SELECT clause ,
- BYPASSING BUFFER in the FROM clause ,
- ORDER BY f1 ... fn in the ORDER-BY clause ,
- aggregate functions in the SELECT clause ,
- when using IS [NOT] NULL WHERE condition ,</b>
or if the generic key part is not qualified in the WHERE-Bedingung for a generically buffered table.
Authorization checks are not supported by the SELECT statement, so you must program these yourself.
In dialog systems, the database system locking mechanism cannot always guarantee to synchronize the simultaneous access of several users to the same dataset. In many cases, it is therefore advisable to use the SAP locking mechanism .
Changes to data in a database are only finalized after a database commit (see LUW ). Prior to this, any database update can be reversed by a database rollback (see Programming transactions ). At the lowest isolation level (see the section on the "uncommitted read" under Locking mechanism ), this can result in the dataset selected by the SELECT command not really being written to the database. While a program is selecting data, a second program can add, change or delete lines at the same time. Then, the changes made by the second program are reversed by rolling back the database system. The selection of the first program thus reflects only a very temporary state of the database. If such "phantom data" is not acceptable for a program, you must either use the SAP locking mechanism or at least set the isolation level of the database system to "committed read" (see Locking mechanism ).
In a SELECT-ENDSELECT loop, the CONTINUE statement terminates the current loop pass prematurely and starts the next.
If one of the statements in a SELECT ... ENDSELECT loop results in a database commit, the cursor belonging to the SELECT ... ENDSELECT loop is lost and the processing terminates with a runtime error. Since each screen change automatically generates a database commit, statements such as CALL SCREEN , CALL DIALOG , CALL TRANSACTION or MESSAGE are not allowed within a SELECT ... ENDSELECT loop.
Related OPEN CURSOR , FETCH und CLOSE CURSOR
SELECT clause
Variants
1. <b>SELECT [SINGLE [FOR UPDATE] | DISTINCT] *
2. SELECT [SINGLE [FOR UPDATE] | DISTINCT] s1 ... sn
3. SELECT [SINGLE [FOR UPDATE] | DISTINCT] (itab)</b> Effect
The result of a SELECT statement is itself a table . The SELECT clause describes which columns this table is supposed to have.
In addition, you can use the optional addition SINGLE or DISTINCT if you want only certain lines of the solution set to be visible for the calling program:
SINGLE The result of the selection is a single record . If this record cannot be uniquely identified, the first line of the solution set is selected. The addition FOR UPDATE protects the selected record against parallel changes by other transactions until the next database commit occurs (see LUW and Database locking ). If the database system detects a deadlock, the result is a runtime error.
DISTINCT Any lines which occur more than once are automatically removed from the selected dataset.
Note
To ensure that a record is uniquely determined, you can fully qualify all fields of the primary key by linking them together with AND in the WHERE condition.
Note
Performance
The additions SINGLE FOR UPDATE and DISTINCT exclude the use of SAP buffering .
The addition DISTINCT requires sorting on the database server and should therefore only be specified if duplicates are likely to occur.
Variant 1
SELECT [SINGLE [FOR UPDATE] | DISTINCT] *
Effect
In the result set, the columns correspond exactly in terms of order, ABAP/4 Dictionary type and length to the fields of the database table (or view ) specified in the FROM clause .
Example
Output all flight connections from Frankfurt to New York:
TABLES SPFLI.
SELECT * FROM SPFLI
WHERE
CITYFROM = 'FRANKFURT' AND
CITYTO = 'NEW YORK'.
WRITE: / SPFLI-CARRID, SPFLI-CONNID.
ENDSELECT.
Example
Output all free seats on the Lufthansa flight 0400 on 28.02.1995:
TABLES SFLIGHT.
DATA SEATSFREE TYPE I.
SELECT SINGLE * FROM SFLIGHT
WHERE
CARRID = 'LH ' AND
CONNID = '0400' AND
FLDATE = '19950228'.
SEATSFREE = SFLIGHT-SEATSMAX - SFLIGHT-SEATSOCC.
WRITE: / SFLIGHT-CARRID, SFLIGHT-CONNID,
SFLIGHT-FLDATE, SEATSFREE.
Variant 2
SELECT [SINGLE [FOR UPDATE] | DISTINCT] s1 ... sn
Effect
The order, ABAP/4 Dictionary type and length of the columns of the result set are explicitly defined by the list s1 ... sn . Each si has the form
ai or ai AS bi .
Here, ai stands either for
a field f of the database table or
a aggregate print.
bi is an alternative name for the i-th column of the result set.
When using INTO CORRESPONDING FIELDS OF wa in the INTO clause , you can specify an alternative column name to assign a column of the result set uniquely to a column of the target area.
An aggregate print uses an aggregate function to group together data from one or all columns of the database table. Aggregate prints consist of three or four components:
An aggregate function immediately followed by an opening parenthesis DISTINCT (optional) The database field f A closing parenthesis
All components of a print must be separated by at least one blank.
The following aggregate functions are available:
MAX Returns the greatest value in the column determined by the database field f for the selected lines. Specifying DISTINCT does not change the result. NULL values are ignored unless all values in a column are NULL values. In this case, the result is NULL .
MIN Returns the smallest value in the column determined by the database field f for the selected lines. Specifying DISTINCT does not change the result. NULL values are ignored unless all values in a column are NULL values. In this case, the result is NULL .
AVG Returns the average value in the column determined by the database field f for the selected lines. AVG can only apply to a numeric field. NULL values are ignored unless all values in a column are NULL values. In this case, the result is NULL .
SUM Returns the sum of all values in the column determined by the database field f for the selected lines. SUM can only apply to a numeric field. NULL values are ignored unless all values in a column are NULL values. In this case, the result is NULL .
COUNT Returns the number of different values in the column determined by the database field f for the selected lines. Specifying DISTINCT is obligatory here. NULL values are ignored unless all values in a column are NULL values. In this case, the result is 0
COUNT( * ) Returns the number of selected lines. If the SELECT command contains a GROUP BY clause , it returns the number of lines for each group. The form COUNT(*) is also allowed.
If ai is a field f , MAX( f ) , MIN( f ) or SUM( f ) , the corresponding column of the result set has the same ABAP/4 Dictionary format as f . With COUNT( f ) or COUNT( * ) , the column has the type INT4 , with AVG( f ) the type FLTP .
If you specify aggregate functions together with one or more database fields in a SELECT clause, all database fields not used in one of the aggregate functions must be listed in the GROUP-BY clause . Here, the result of the selection is a table.
If only aggregate functions occur in the SELECT clause, the result of the selection is a single record. Here, the SELECT command is not followed later by an ENDSELECT .
Notes
This variant is not available for pooled tables and cluster tables .
If the SELECT clause contains a database field of type LCHAR or LRAW , you must specify the appropriate length field immediately before.
Notes
Performance
Specifying aggregate functions excludes the use of SAP buffering .
Since many database systems do not manage the number of table lines and therefore have to retrieve this at some cost, the function COUNT( * ) is not suitable for checking whether a table contains a line or not. To do this, it is best to use SELECT SINGLE f ... for any table field f .
If you only want to select certain columns of a database table, you are recommended to specify a list of fields in the SELECT clause or to use a View .
Examples
Output all flight destinations for Lufthansa flights from Frankfurt:
TABLES SPFLI.
DATA TARGET LIKE SPFLI-CITYTO.
SELECT DISTINCT CITYTO
INTO TARGET FROM SPFLI
WHERE
CARRID = 'LH ' AND
CITYFROM = 'FRANKFURT'.
WRITE: / TARGET.
ENDSELECT.
Output the number of airline carriers which fly to New York:
TABLES SPFLI.
DATA COUNT TYPE I.
SELECT COUNT( DISTINCT CARRID )
INTO COUNT FROM SPFLI
WHERE
CITYTO = 'NEW YORK'.
WRITE: / COUNT.
Output the number of passengers, the total weight and the average weight of luggage for all Lufthansa flights on 28.02.1995:
TABLES SBOOK.
DATA: COUNT TYPE I, SUM TYPE P DECIMALS 2, AVG TYPE F.
DATA: CONNID LIKE SBOOK-CONNID.
SELECT CONNID COUNT( * ) SUM( LUGGWEIGHT ) AVG( LUGGWEIGHT )
INTO (CONNID, COUNT, SUM, AVG)
FROM SBOOK
WHERE
CARRID = 'LH ' AND
FLDATE = '19950228'
GROUP BY CONNID.
WRITE: / CONNID, COUNT, SUM, AVG.
ENDSELECT.
Variant 3
SELECT [SINGLE [FOR UPDATE] | DISTINCT] (itab)
Effect
Works like SELECT [SINGLE [FOR UPDATE] | DISTINCT] s1 ... sn if the internal table itab contains the list s1 ... sn as ABAP/4 source code, and like SELECT [SINGLE [FOR UPDATE] | DISTINCT] * , if itab is empty. The internal table itab can only have one field which must be of type C and cannot be more than 72 characters long. itab must appear in parentheses and there should be no blanks between the parentheses and the table name.
Note
With this variant, the same restrictions apply as for SELECT [SINGLE [FOR UPDATE] | DISTINCT] s1 ... sn .
Example
Output all Lufthansa flight routes:
TABLES: SPFLI.
DATA: FTAB(72) OCCURS 5 WITH HEADER LINE.
REFRESH FTAB.
FTAB = 'CITYFROM'. APPEND FTAB.
FTAB = 'CITYTO'. APPEND FTAB.
SELECT DISTINCT (FTAB)
INTO CORRESPONDING FIELDS OF SPFLI
FROM SPFLI
WHERE
CARRID = 'LH'.
WRITE: / SPFLI-CITYFROM, SPFLI-CITYTO.
ENDSELECT.
check this one:
http://www.sts.tu-burg.de/teaching/sap_r3/ABAP4/select.htm -
Updating results of a select stmt
Hello gurus,
Can anybody throw some light on the usage of the following update stmt, in terms of its perfomance ?
"UPDATE (<SELECT stmt>)
SET < column > = < value >
WHERE < column > < condition >"
In my case, the select stmt that I plan is use is a join of 6 tables & it looks something like this :
UPDATE (
select t2.order_id, t1.price,t5.discount, t4.original_price
from table1 t1, table2 t2, table3 t3, table4 t4, table5 t5, table6 t6
where t1.order_loc_id = t2.order_loc_id
and t1.prod_id = t4.prod_id
and t1.prod_id = t5.prod_id
and t5.id = t6.id
and t3.id = t6.hdr_nbr
and t3.order_id = t2.order_id
and round((t1.price+t5.discount),2) > round(t4.original_price,2)
and t4.invnm = 'INVN'
and t2.order_id = 6
) p
SET p.price = (p.original_price - p.discount)
WHERE p.order_id = 6;
I was wondering if this stmt would be hv any performance issue ?
Also, would all the tables in the select hv a lock on them ? (not quite sure how the table/row get locked) ?
Regards,
Madhu.You don't need the WHERE order_id = 6 in your outer statement as it's also in the inner statement.
Also, you must have all the proper primary key or unique indexes in place or you will get the "...maps to non-key preserved table" error.
I was wondering if this stmt would be hv any performance issue ?There's no way we can tell. You have to post explain plans and traces. Same as any other sql statement. -
How can we find the most usage and lowest usage of table in Sql Server by T-SQL
how can we find the most usage and lowest usage of table in Sql Server by T-SQL
The table has time stamp column
StartedOn datetime
EndedOn datetimeThe Below query has been used , but the textdata column doesnot include the name of the table ServiceLog.
SELECT
FROM
databasename,
duration
fn_trace_gettable('F:\Program
Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Log\log_148.trc',
default)
WHERE
DATABASENAME='ZTCFUTURE'
AND TEXTDATA
IS
NOT
NULL
--AND TEXTDATA LIKE 'SERVICE%'
order
by cpu
desc; -
PL/SQL 101 : Cursors and SQL Projection
PL/SQL 101 : Cursors and SQL Projection
This is not a question, it's a forum article, in reponse to the number of questions we get regarding a "dynamic number of columns" or "rows to columns"
There are two integral parts to an SQL Select statement that relate to what data is selected. One is Projection and the other is Selection:-
Selection is the one that we always recognise and use as it forms the WHERE clause of the select statement, and hence selects which rows of data are queried.
The other, SQL Projection is the one that is less understood, and the one that this article will help to explain.
In short, SQL Projection is the collective name for the columns that are Selected and returned from a query.
So what? Big deal eh? Why do we need to know this?
The reason for knowing this is that many people are not aware of when SQL projection comes into play when you issue a select statement. So let's take a basic query...
First create some test data...
create table proj_test as
select 1 as id, 1 as rn, 'Fred' as nm from dual union all
select 1,2,'Bloggs' from dual union all
select 2,1,'Scott' from dual union all
select 2,2,'Smith' from dual union all
select 3,1,'Jim' from dual union all
select 3,2,'Jones' from dual
... and now query that data...
SQL> select * from proj_test;
ID RN NM
1 1 Fred
1 2 Bloggs
2 1 Scott
2 2 Smith
3 1 Jim
3 2 Jones
6 rows selected.
OK, so what is that query actually doing?
To know that we need to consider that all queries are cursors and all cursors are processed in a set manner, roughly speaking...
1. The cursor is opened
2. The query is parsed
3. The query is described to know the projection (what columns are going to be returned, names, datatypes etc.)
4. Bind variables are bound in
5. The query is executed to apply the selection and identify the data to be retrieved
6. A row of data is fetched
7. The data values from the columns within that row are extracted into the known projection
8. Step 6 and 7 are repeated until there is no more data or another condition ceases the fetching
9. The cursor is closed
The purpose of the projection being determined is so that the internal processing of the cursor can allocate memory etc. ready to fetch the data into. We won't get to see that memory allocation happening easily, but we can see the same query being executed in these steps if we do it programatically using the dbms_sql package...
CREATE OR REPLACE PROCEDURE process_cursor (p_query in varchar2) IS
v_sql varchar2(32767) := p_query;
v_cursor number; -- A cursor is a handle (numeric identifier) to the query
col_cnt integer;
v_n_val number; -- numeric type to fetch data into
v_v_val varchar2(20); -- varchar type to fetch data into
v_d_val date; -- date type to fetch data into
rec_tab dbms_sql.desc_tab; -- table structure to hold sql projection info
dummy number;
v_ret number; -- number of rows returned
v_finaltxt varchar2(100);
col_num number;
BEGIN
-- 1. Open the cursor
dbms_output.put_line('1 - Opening Cursor');
v_cursor := dbms_sql.open_cursor;
-- 2. Parse the cursor
dbms_output.put_line('2 - Parsing the query');
dbms_sql.parse(v_cursor, v_sql, dbms_sql.NATIVE);
-- 3. Describe the query
-- Note: The query has been described internally when it was parsed, but we can look at
-- that description...
-- Fetch the description into a structure we can read, returning the count of columns that has been projected
dbms_output.put_line('3 - Describing the query');
dbms_sql.describe_columns(v_cursor, col_cnt, rec_tab);
-- Use that description to define local datatypes into which we want to fetch our values
-- Note: This only defines the types, it doesn't fetch any data and whilst we can also
-- determine the size of the columns we'll just use some fixed sizes for this example
dbms_output.put_line(chr(10)||'3a - SQL Projection:-');
for j in 1..col_cnt
loop
v_finaltxt := 'Column Name: '||rpad(upper(rec_tab(j).col_name),30,' ');
case rec_tab(j).col_type
-- if the type of column is varchar2, bind that to our varchar2 variable
when 1 then
dbms_sql.define_column(v_cursor,j,v_v_val,20);
v_finaltxt := v_finaltxt||' Datatype: Varchar2';
-- if the type of the column is number, bind that to our number variable
when 2 then
dbms_sql.define_column(v_cursor,j,v_n_val);
v_finaltxt := v_finaltxt||' Datatype: Number';
-- if the type of the column is date, bind that to our date variable
when 12 then
dbms_sql.define_column(v_cursor,j,v_d_val);
v_finaltxt := v_finaltxt||' Datatype: Date';
-- ...Other types can be added as necessary...
else
-- All other types we'll assume are varchar2 compatible (implicitly converted)
dbms_sql.DEFINE_COLUMN(v_cursor,j,v_v_val,2000);
v_finaltxt := v_finaltxt||' Datatype: Varchar2 (implicit)';
end case;
dbms_output.put_line(v_finaltxt);
end loop;
-- 4. Bind variables
dbms_output.put_line(chr(10)||'4 - Binding in values');
null; -- we have no values to bind in for our test
-- 5. Execute the query to make it identify the data on the database (Selection)
-- Note: This doesn't fetch any data, it just identifies what data is required.
dbms_output.put_line('5 - Executing the query');
dummy := dbms_sql.execute(v_cursor);
-- 6.,7.,8. Fetch the rows of data...
dbms_output.put_line(chr(10)||'6,7 and 8 Fetching Data:-');
loop
-- 6. Fetch next row of data
v_ret := dbms_sql.fetch_rows(v_cursor);
-- If the fetch returned no row then exit the loop
exit when v_ret = 0;
-- 7. Extract the values from the row
v_finaltxt := null;
-- loop through each of the Projected columns
for j in 1..col_cnt
loop
case rec_tab(j).col_type
-- if it's a varchar2 column
when 1 then
-- read the value into our varchar2 variable
dbms_sql.column_value(v_cursor,j,v_v_val);
v_finaltxt := ltrim(v_finaltxt||','||rpad(v_v_val,20,' '),',');
-- if it's a number column
when 2 then
-- read the value into our number variable
dbms_sql.column_value(v_cursor,j,v_n_val);
v_finaltxt := ltrim(v_finaltxt||','||to_char(v_n_val,'fm999999'),',');
-- if it's a date column
when 12 then
-- read the value into our date variable
dbms_sql.column_value(v_cursor,j,v_d_val);
v_finaltxt := ltrim(v_finaltxt||','||to_char(v_d_val,'DD/MM/YYYY HH24:MI:SS'),',');
else
-- read the value into our varchar2 variable (assumes it can be implicitly converted)
dbms_sql.column_value(v_cursor,j,v_v_val);
v_finaltxt := ltrim(v_finaltxt||',"'||rpad(v_v_val,20,' ')||'"',',');
end case;
end loop;
dbms_output.put_line(v_finaltxt);
-- 8. Loop to fetch next row
end loop;
-- 9. Close the cursor
dbms_output.put_line(chr(10)||'9 - Closing the cursor');
dbms_sql.close_cursor(v_cursor);
END;
SQL> exec process_cursor('select * from proj_test');
1 - Opening Cursor
2 - Parsing the query
3 - Describing the query
3a - SQL Projection:-
Column Name: ID Datatype: Number
Column Name: RN Datatype: Number
Column Name: NM Datatype: Varchar2
4 - Binding in values
5 - Executing the query
6,7 and 8 Fetching Data:-
1 ,1 ,Fred
1 ,2 ,Bloggs
2 ,1 ,Scott
2 ,2 ,Smith
3 ,1 ,Jim
3 ,2 ,Jones
1 ,3 ,Freddy
1 ,4 ,Fud
9 - Closing the cursor
PL/SQL procedure successfully completed.
So, what's really the point in knowing when SQL Projection occurs in a query?
Well, we get many questions asking "How do I convert rows to columns?" (otherwise known as a pivot) or questions like "How can I get the data back from a dynamic query with different columns?"
Let's look at a regular pivot. We would normally do something like...
SQL> select id
2 ,max(decode(rn,1,nm)) as nm_1
3 ,max(decode(rn,2,nm)) as nm_2
4 from proj_test
5 group by id
6 /
ID NM_1 NM_2
1 Fred Bloggs
2 Scott Smith
3 Jim Jones
(or, in 11g, use the new PIVOT statement)
but many of these questioners don't understand it when they say their issue is that, they have an unknown number of rows and don't know how many columns it will have, and they are told that you can't do that in a single SQL statement. e.g.
SQL> insert into proj_test (id, rn, nm) values (1,3,'Freddy');
1 row created.
SQL> select id
2 ,max(decode(rn,1,nm)) as nm_1
3 ,max(decode(rn,2,nm)) as nm_2
4 from proj_test
5 group by id
6 /
ID NM_1 NM_2
1 Fred Bloggs
2 Scott Smith
3 Jim Jones
... it's not giving us this 3rd entry as a new column and we can only get that by writing the expected columns into the query, but then what if more columns are added after that etc.
If we look back at the steps of a cursor we see again that the description and projection of what columns are returned by a query happens before any data is fetched back.
Because of this, it's not possible to have the query return back a number of columns that are based on the data itself, as no data has been fetched at the point the projection is required.
So, what is the answer to getting an unknown number of columns in the output?
1) The most obvious answer is, don't use SQL to try and pivot your data. Pivoting of data is more of a reporting requirement and most reporting tools include the ability to pivot data either as part of the initial report generation or on-the-fly at the users request. The main point about using the reporting tools is that they query the data first and then the pivoting is simply a case of manipulating the display of those results, which can be dynamically determined by the reporting tool based on what data there is.
2) The other answer is to write dynamic SQL. Because you're not going to know the number of columns, this isn't just a simple case of building up a SQL query as a string and passing it to the EXECUTE IMMEDIATE command within PL/SQL, because you won't have a suitable structure to read the results back into as those structures must have a known number of variables for each of the columns at design time, before the data is know. As such, inside PL/SQL code, you would have to use the DBMS_SQL package, just like in the code above that showed the workings of a cursor, as the columns there are referenced by position rather than name, and you have to deal with each column seperately. What you do with each column is up to you... store them in an array/collection, process them as you get them, or whatever. They key thing though with doing this is that, just like the reporting tools, you would need to process the data first to determine what your SQL projection is, before you execute the query to fetch the data in the format you want e.g.
create or replace procedure dyn_pivot is
v_sql varchar2(32767);
-- cursor to find out the maximum number of projected columns required
-- by looking at the data
cursor cur_proj_test is
select distinct rn
from proj_test
order by rn;
begin
v_sql := 'select id';
for i in cur_proj_test
loop
-- dynamically add to the projection for the query
v_sql := v_sql||',max(decode(rn,'||i.rn||',nm)) as nm_'||i.rn;
end loop;
v_sql := v_sql||' from proj_test group by id order by id';
dbms_output.put_line('Dynamic SQL Statement:-'||chr(10)||v_sql||chr(10)||chr(10));
-- call our DBMS_SQL procedure to process the query with it's dynamic projection
process_cursor(v_sql);
end;
SQL> exec dyn_pivot;
Dynamic SQL Statement:-
select id,max(decode(rn,1,nm)) as nm_1,max(decode(rn,2,nm)) as nm_2,max(decode(rn,3,nm)) as nm_3 from proj_test group by id order by id
1 - Opening Cursor
2 - Parsing the query
3 - Describing the query
3a - SQL Projection:-
Column Name: ID Datatype: Number
Column Name: NM_1 Datatype: Varchar2
Column Name: NM_2 Datatype: Varchar2
Column Name: NM_3 Datatype: Varchar2
4 - Binding in values
5 - Executing the query
6,7 and 8 Fetching Data:-
1 ,Fred ,Bloggs ,Freddy
2 ,Scott ,Smith ,
3 ,Jim ,Jones ,
9 - Closing the cursor
PL/SQL procedure successfully completed.
... and if more data is added ...
SQL> insert into proj_test (id, rn, nm) values (1,4,'Fud');
1 row created.
SQL> exec dyn_pivot;
Dynamic SQL Statement:-
select id,max(decode(rn,1,nm)) as nm_1,max(decode(rn,2,nm)) as nm_2,max(decode(rn,3,nm)) as nm_3,max(decode(rn,4,nm)) as nm_4 from proj_test group by id order by id
1 - Opening Cursor
2 - Parsing the query
3 - Describing the query
3a - SQL Projection:-
Column Name: ID Datatype: Number
Column Name: NM_1 Datatype: Varchar2
Column Name: NM_2 Datatype: Varchar2
Column Name: NM_3 Datatype: Varchar2
Column Name: NM_4 Datatype: Varchar2
4 - Binding in values
5 - Executing the query
6,7 and 8 Fetching Data:-
1 ,Fred ,Bloggs ,Freddy ,Fud
2 ,Scott ,Smith , ,
3 ,Jim ,Jones , ,
9 - Closing the cursor
PL/SQL procedure successfully completed.
Of course there are other methods, using dynamically generated scripts etc. (see Re: 4. How do I convert rows to columns?), but the above simply demonstrates that:-
a) having a dynamic projection requires two passes of the data; one to dynamically generate the query and another to actually query the data,
b) it is not a good idea in most cases as it requires code to handle the results dynamically rather than being able to simply query directly into a known structure or variables, and
c) a simple SQL statement cannot have a dynamic projection.
Most importantly, dynamic queries prevent validation of your queries at the time your code is compiled, so the compiler can't check that the column names are correct or the tables names, or that the actual syntax of the generated query is correct. This only happens at run-time, and depending upon the complexity of your dynamic query, some problems may only be experienced under certain conditions. In effect you are writing queries that are harder to validate and could potentially have bugs in them that would are not apparent until they get to a run time environment. Dynamic queries can also introduce the possibility of SQL injection (a potential security risk), especially if a user is supplying a string value into the query from an interface.
To summarise:-
The projection of an SQL statement must be known by the SQL engine before any data is fetched, so don't expect SQL to magically create columns on-the-fly based on the data it's retrieving back; and, if you find yourself thinking of using dynamic SQL to get around it, just take a step back and see if what you are trying to achieve may be better done elsewhere, such as in a reporting tool or the user interface.
Other articles in the PL/SQL 101 series:-
PL/SQL 101 : Understanding Ref Cursors
PL/SQL 101 : Exception Handlingexcellent article. However there is one thing which is slightly erroneous. You don't need a type to be declared in the database to fetch the data, but you do need to declare a type;
here is one of my unit test scripts that does just that.
DECLARE
PN_CARDAPPL_ID NUMBER;
v_Return Cci_Standard.ref_cursor;
type getcardapplattrval_recordtype
Is record
(cardappl_id ci_cardapplattrvalue.cardappl_ID%TYPE,
tag ci_cardapplattrvalue.tag%TYPE,
value ci_cardapplattrvalue.value%TYPE
getcardapplattrvalue_record getcardapplattrval_recordtype;
BEGIN
PN_CARDAPPL_ID := 1; --value must be supplied
v_Return := CCI_GETCUSTCARD.GETCARDAPPLATTRVALUE(
PN_CARDAPPL_ID => PN_CARDAPPL_ID
loop
fetch v_return
into getcardapplattrvalue_record;
dbms_output.put_line('Cardappl_id=>'||getcardapplattrvalue_record.cardappl_id);
dbms_output.put_line('Tag =>'||getcardapplattrvalue_record.tag);
dbms_output.put_line('Value =>'||getcardapplattrvalue_record.value);
exit when v_Return%NOTFOUND;
end loop;
END; -
Using column number inplace of column name in SQL Select statement
Is there a way to run sql select statements with column numbers in
place of column names?
Current SQL
select AddressId,Name,City from AddressIs this possible
select 1,2,5 from AddressThanks in Advanceuser10962462 wrote:
well, ok, it's not possible with SQL, but how about PL/SQL?As mentioned, using DBMS_SQL you can only really use positional notation... and you can also use those positions to get the other information such as what the column is called, what it's datatype is etc.
CREATE OR REPLACE PROCEDURE run_query(p_sql IN VARCHAR2) IS
v_v_val VARCHAR2(4000);
v_n_val NUMBER;
v_d_val DATE;
v_ret NUMBER;
c NUMBER;
d NUMBER;
col_cnt INTEGER;
f BOOLEAN;
rec_tab DBMS_SQL.DESC_TAB;
col_num NUMBER;
v_rowcount NUMBER := 0;
BEGIN
-- create a cursor
c := DBMS_SQL.OPEN_CURSOR;
-- parse the SQL statement into the cursor
DBMS_SQL.PARSE(c, p_sql, DBMS_SQL.NATIVE);
-- execute the cursor
d := DBMS_SQL.EXECUTE(c);
-- Describe the columns returned by the SQL statement
DBMS_SQL.DESCRIBE_COLUMNS(c, col_cnt, rec_tab);
-- Bind local return variables to the various columns based on their types
FOR j in 1..col_cnt
LOOP
CASE rec_tab(j).col_type
WHEN 1 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_v_val,2000); -- Varchar2
WHEN 2 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_n_val); -- Number
WHEN 12 THEN DBMS_SQL.DEFINE_COLUMN(c,j,v_d_val); -- Date
ELSE
DBMS_SQL.DEFINE_COLUMN(c,j,v_v_val,2000); -- Any other type return as varchar2
END CASE;
END LOOP;
-- Display what columns are being returned...
DBMS_OUTPUT.PUT_LINE('-- Columns --');
FOR j in 1..col_cnt
LOOP
DBMS_OUTPUT.PUT_LINE(rec_tab(j).col_name||' - '||case rec_tab(j).col_type when 1 then 'VARCHAR2'
when 2 then 'NUMBER'
when 12 then 'DATE'
else 'Other' end);
END LOOP;
DBMS_OUTPUT.PUT_LINE('-------------');
-- This part outputs the DATA
LOOP
-- Fetch a row of data through the cursor
v_ret := DBMS_SQL.FETCH_ROWS(c);
-- Exit when no more rows
EXIT WHEN v_ret = 0;
v_rowcount := v_rowcount + 1;
DBMS_OUTPUT.PUT_LINE('Row: '||v_rowcount);
DBMS_OUTPUT.PUT_LINE('--------------');
-- Fetch the value of each column from the row
FOR j in 1..col_cnt
LOOP
-- Fetch each column into the correct data type based on the description of the column
CASE rec_tab(j).col_type
WHEN 1 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_v_val);
DBMS_OUTPUT.PUT_LINE(rec_tab(j).col_name||' : '||v_v_val);
WHEN 2 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_n_val);
DBMS_OUTPUT.PUT_LINE(rec_tab(j).col_name||' : '||v_n_val);
WHEN 12 THEN DBMS_SQL.COLUMN_VALUE(c,j,v_d_val);
DBMS_OUTPUT.PUT_LINE(rec_tab(j).col_name||' : '||to_char(v_d_val,'DD/MM/YYYY HH24:MI:SS'));
ELSE
DBMS_SQL.COLUMN_VALUE(c,j,v_v_val);
DBMS_OUTPUT.PUT_LINE(rec_tab(j).col_name||' : '||v_v_val);
END CASE;
END LOOP;
DBMS_OUTPUT.PUT_LINE('--------------');
END LOOP;
-- Close the cursor now we have finished with it
DBMS_SQL.CLOSE_CURSOR(c);
END;
SQL> exec run_query('select empno, ename, deptno, sal from emp where deptno = 10');
-- Columns --
EMPNO - NUMBER
ENAME - VARCHAR2
DEPTNO - NUMBER
SAL - NUMBER
Row: 1
EMPNO : 7782
ENAME : CLARK
DEPTNO : 10
SAL : 2450
Row: 2
EMPNO : 7839
ENAME : KING
DEPTNO : 10
SAL : 5000
Row: 3
EMPNO : 7934
ENAME : MILLER
DEPTNO : 10
SAL : 1300
PL/SQL procedure successfully completed.
SQL> exec run_query('select * from emp where deptno = 10');
-- Columns --
EMPNO - NUMBER
ENAME - VARCHAR2
JOB - VARCHAR2
MGR - NUMBER
HIREDATE - DATE
SAL - NUMBER
COMM - NUMBER
DEPTNO - NUMBER
Row: 1
EMPNO : 7782
ENAME : CLARK
JOB : MANAGER
MGR : 7839
HIREDATE : 09/06/1981 00:00:00
SAL : 2450
COMM :
DEPTNO : 10
Row: 2
EMPNO : 7839
ENAME : KING
JOB : PRESIDENT
MGR :
HIREDATE : 17/11/1981 00:00:00
SAL : 5000
COMM :
DEPTNO : 10
Row: 3
EMPNO : 7934
ENAME : MILLER
JOB : CLERK
MGR : 7782
HIREDATE : 23/01/1982 00:00:00
SAL : 1300
COMM :
DEPTNO : 10
PL/SQL procedure successfully completed.
SQL> exec run_query('select * from dept where deptno = 10');
-- Columns --
DEPTNO - NUMBER
DNAME - VARCHAR2
LOC - VARCHAR2
Row: 1
DEPTNO : 10
DNAME : ACCOUNTING
LOC : NEW YORK
PL/SQL procedure successfully completed.
SQL> -
How do i include this 'select' stmt in a 'procedure'.
create or replace procedure proc1
AS
BEGIN
select table1.name,table1.symbol,table1.quantity,table2.price,(table1.quantity*table2.price) AS Total
from table1,table2
where table2.date=(select date from
table2,table1,table3
where table1.date=table3.date
AND table1symbol=table2.symbol)
END;
here, name and symbol are varchar2
and quantity and price are number
date is date
the main problem is tht select in a procedure requires an INTO clause
The normal select query is running but i am unable to transform it into a procedure using variables and cursors
can u solve this prob for me...??> The normal select query is running but i am unable to
transform it into a procedure using variables and cursors
There are a couple of ways to define cursors - even a plain SQL as what you have posted is a cursor.
The details:
Oracle® Database PL/SQL User's Guide and Reference
Chapter 6. Performing SQL Operations from PL/SQL
http://download-east.oracle.com/docs/cd/B19306_01/appdev.102/b14261/toc.htm
The basics - for an explicit cursor you want to use bulk collection 99% of the time in order for performance and scalability. So (assuming the SQL has been analysed and optimised):
create or replace procedure proc1 as
-- define an explicit cursor
cursor myCursor is
select
table1.name,table1.symbol,table1.quantity,
table2.price,(table1.quantity*table2.price) AS Total
from table1,table2
where table2.date=(
select
date
from table2,table1,table3
where table1.date=table3.date
and table1.symbol=table2.symbol
-- define an array type for fetching the rows into
type TBuffer is table of myCursor%ROWTYPE;
-- define an array for fetching the rows into
buffer TBuffer;
begin
open myCursor;
loop
-- fetch a max of 1000 rows at a time
fetch myCursor bulk collect into buffer limit 1000;
-- process these rows
for i in 1..buffer.Count
loop
-- buffer needs to be subscripted to get to the row,
-- and buffer contains the columns that were selected
-- from the tables, e.g.
DBMS_OUTPUT.put_line( 'Processing '||buffer(i).name );
Proc2( buffer(i) );
end loop;
exit when myCursor%NOTFOUND;
end loop;
close myCursor;
end;
All the details of bulk processing and cursors are in the PL/SQL User Guide - with examples. -
PL/SQL select list from query
Hello,
I am trying to modifying a PL/SQL process. Wherever there was a reference to the Application ID, I wanted to change it to refer to the Application Alias.
Here is the original code:
declare
cursor app_cur is
select aa.application_id||' - '||aa.application_name app_name,
aa.application_id
from apex_applications aa
where exists (select 1
from profiles p
where p.application_id = aa.application_id);
cursor user_app_cur (p_user number, p_app number) is
select to_char(profile_id)
from user_app_profiles
where user_id = p_user
and application_id = p_app;
v_profile varchar2(10);
v_count number := 0;
v_class varchar2(15);
begin
htp.p('<table class="t3standardalternatingrowcolors" cellpadding="0" cellspacing="0">');
htp.p('<tr><th class="t3header" >Application</th><th class="t3header" >Profile</th></tr>');
for app in app_cur loop
v_count := v_count + 1;
if mod(v_count,2) = 1 then
v_class := 't3dataalt';
else
v_class := 't3data';
end if;
open user_app_cur(:P3_USER_ID, app.application_id);
fetch user_app_cur
into v_profile;
if user_app_cur%notfound then
v_profile := 'NONE';
end if;
close user_app_cur;
htp.p('<tr><td class="'||v_class||'">'||app.app_name||
'</td><td class="'||v_class||'">'||
apex_item.select_list_from_query(40, v_profile,
'select description, profile_id from profiles where application_id = '||app.application_id,
null, 'YES', 'NONE', 'No Profile Assigned', null, null, 'NO')||
apex_item.hidden(41,app.application_id) ||
'</td></tr>');
end loop;
htp.p('</table>');
end;Here is my revised code:
declare
cursor app_cur is
select aa.alias||' - '||aa.application_name app_name,
aa.alias
from apex_applications aa
where exists (select 1
from profiles p
where p.application_alias = aa.alias);
cursor user_app_cur (p_user number, p_app varchar2) is
select to_char(profile_id)
from user_app_profiles
where user_id = p_user
and application_alias = p_app;
v_profile varchar2(10);
v_count number := 0;
v_class varchar2(15);
begin
htp.p('<table class="t3standardalternatingrowcolors" cellpadding="0" cellspacing="0">');
htp.p('<tr><th class="t3header" >Application</th><th class="t3header" >Profile</th></tr>');
for app in app_cur loop
v_count := v_count + 1;
if mod(v_count,2) = 1 then
v_class := 't3dataalt';
else
v_class := 't3data';
end if;
open user_app_cur(:P3_USER_ID, app.alias);
fetch user_app_cur
into v_profile;
if user_app_cur%notfound then
v_profile := 'NONE';
end if;
close user_app_cur;
htp.p('<tr><td class="'||v_class||'">'||app.app_name||
'</td><td class="'||v_class||'">'||
apex_item.select_list_from_query(40, v_profile,
'select description, profile_id from profiles where application_alias = '||app.alias,
null, 'YES', 'NONE', 'No Profile Assigned', null, null, 'NO')||
apex_item.hidden(41,app.alias) ||
'</td></tr>');
end loop;
htp.p('</table>');
end;Here is the error:
ORA-06550: line 1, column 153: PL/SQL: ORA-00904: "F109NEWNAME": invalid identifier ORA-06550: line 1, column 7: PL/SQL: SQL Statement ignored
I think that the problem is in the table/LOV generation near the end, but I don't fully understand the apex_item.select_list_from_query function as it is written (I didn't write it).
Any help is greatly appreciated.
Thanks,
MattHi Matt,
This line:
'select description, profile_id from profiles where application_alias = '||app.aliaswould become:
select description, profile_id from profiles where application_alias = F109NEWNAMEif F109NEWNAME was the app_alias. SQL would see F109NEWNAME as a variable as it is not in quotes. Therefore, you should change the line to:
'select description, profile_id from profiles where application_alias = ''' || app.alias || ''''to end up with:
select description, profile_id from profiles where application_alias = 'F109NEWNAME'which would make more sense
Andy -
Use of cursors insted of select statements
could any one please explain what is the advantage of using cursors instead of simple select statements
thanks
sibyA benefit to using an explicit cursor rather than a select statement, is for the NO_DATA_FOUND exception. Its kind of like a free IF statment. IF no data is found, then stop.
if you write a select statement, and no data is returned, you SHOULD code for the NO_DATA_FOUND exception. Often people say, "i'll ALWAYS get a row returned". but you should always cover your code "just in case". so you must code an exception...
declare
v_var varchar2(1);
procedure do_something(p_parm varchar2) is
begin
null;
end do_something;
procedure log_error is
begin
null;
end log_error;
begin <<main>>
do_something('x');
begin <<selectblock>>
select dummy
into v_var
from dual
where dummy = 'a';
do_something(v_var);
exception
when no_data_found then
log_error;
end selectblock;
do_something (v_var||'abc');
end main;
if you use an explicit cursor instead, you don't need to code for the NO_DATA_FOUND. If an explicit cursor opens and finds no rows, there are simply no rows. of course, you don't need a loop if you expect only 1 row returned under normal circumstances.
BTW, don' forget that SQL%ROWCOUNT and your_cursor%ROWCOUNT are not initialized. There is a null, until a row is successfully fetched. therefore if no rows are returned at all, %ROWCOUNT is NULL.
declare
v_var varchar2(1);
cursor my_cur is
select dummy
from dual
where dummy = 'a';
procedure do_something(p_parm varchar2) is
begin
null;
end do_something;
procedure log_error is
begin
null;
end log_error;
begin << main>>
for cur_rec in my_cur loop
dbms_output.put_line('inside');
begin <<loop_block>>
if nvl(my_cur%rowcount,0) > 1 then
do_something(cur_rec.dummy);
else
log_error;
end if;
end loop_block;
end loop;
end main;
/ -
Alternative for Cursor in SQL Server 2012
Hi all,
I keen to know Alternative for Cursor in SQL Server 2012. Why everyone telling Cursor have performance impact. Any other alternative for row by row comparison like Array in SQL 2012 ?
ThanksIt is not the cursor that kills you - it is the loop as such. I've seen more than one example of a poor man's cursor, where they have selected TOP 1 from a #temp ORDER BY, and several operations on the temp table - which is completely void of indexes,
making the operations for the loop control the slowest in the batch. So you use cursor when you need to iterate.
But in many cases, you should work and think set-based instead.
Erland Sommarskog, SQL Server MVP, [email protected] -
How to convert update,delete statement into select stmt
Hi all,
I have a field called dml_stmt, i am getting the dml statement has input from the user.
My requirement is, if user is giving "update set col_name = 'xyz' from table_name where codition = 'aa'", before updating the table, i need to get old values from the table and put it in the audit table
For that,i need to convert those update statement into select stmt and need to execute the query to get the data and then i will put it in the audit table..
can anyone guide how to convert the update or delete stmt into select(need to write in pl/sql)
Please do needfull things ......
Regards,
JameMaybe I'm missing something, but why would auditing help here? It sounds like the user wants to know the prior values of the data, not the SQL UPDATE statement that was issued. Auditing would tell you that a table was updated, fine-grained auditing would tell you what the UPDATE statement was, but you'd need something else to capture the state of the data prior to the update.
Depending on why putting triggers on every table was discounted, you may also want to take a look at using Workspace Manager or Total Recall (in 11g) to track a history of data changes. But triggers would be the common solution to this sort of problem.
Justin
Maybe you are looking for
-
When trying to update Apps in iTunes on my computer my old Apple ID appears, which is no longer in use and has no password; even when I try to create a password for this Old ID, Apple won't let me. When I go into see my Account settings My new Apple
-
Report to check all cost object balances are Zero in Monthend
Dear Friends, We are facing an issue in every monthend while doing FI and COPA reconciliation that some balances are left in cost objects. Can any one please suggest any single report if any which will show balances in all cost objects instead of ind
-
Bug with swc folders and library projects?
Hi guys, hope someone can help here. We are just in the process of starting a fairly large flex project and we were trying to work out a solution so that I as a designer can view and edit custom components with visual styles applied. Now I know that
-
Whenever I try to sync either my iPhone4 or iPad I get the following message. "The iPhone (or iPad) cannot be synched. The required file cannot be found." My music will sync but none of my videos or photos will. Please help me somebody. Thanks.
-
Looking for something similar to Slideshow Pro...
I'm looking for something that my clients can upload their photos to a page on their website via some sort of admin interface such as Slideshow Pro had. They have shut down their site. They were Flash based, although you could still view the slides