Easier way than NDS
Somebody posted a question about a dynamic NDS example found in the Oracle Database 11g PL/SQL Programming book on page 388. They asked if there was an easier way.
The answer is yes. Here’s a different example implementing the same concept on Native Dynamic SQL (NDS) with an input parameter. I borrowed it from the example I used for an Oracle framework to mimic the MySQL ENUM data type.
Basically, the following shows how you write a function using a dynamic NDS statement with an input parameter.
CREATE OR REPLACE FUNCTION proper_item_type ( item_type_in VARCHAR2 ) RETURN VARCHAR2 IS -- Define a weakly typed system reference cursor. item_cursor SYS_REFCURSOR; -- Define a target variable for the query result. item_type_out VARCHAR2(30); -- Create NDS statement, with a bind or placeholder variable. stmt VARCHAR2(2000) := 'SELECT type_name ' || 'FROM item_type ' || 'WHERE UPPER(type_name) = UPPER(:type_name_in)'; BEGIN -- Open the cursor and dynamically assign the function actual parameter. OPEN item_cursor FOR stmt USING item_type_in; -- Fetch the first row return and return the value. FETCH item_cursor INTO item_type_out; -- CLose the cursor. CLOSE item_cursor; -- Return the value. RETURN item_type_out; END; / |
This is certainly overkill if you only want to substitute a single parameter into a cursor. A simpler approach would be to write a dynamic cursor, and then open the cursor by passing the actual parameter. Here’s that example.
CREATE OR REPLACE FUNCTION proper_item_type ( item_type_in VARCHAR2 ) RETURN VARCHAR2 IS -- Define a dynamic cursor. CURSOR c (item_type_name VARCHAR2) IS SELECT type_name FROM item_type WHERE UPPER(type_name) = UPPER(item_type_name); BEGIN -- Open the cursor and dynamically assign the function actual parameter. FOR i IN c(item_type_in) LOOP RETURN i.type_name; END LOOP; END; / |
An even more primitive approach relies on implicit assignment, like the following:
CREATE OR REPLACE FUNCTION proper_item_type ( item_type_in VARCHAR2 ) RETURN VARCHAR2 IS BEGIN -- Open the cursor and rely on implicit assignment within the cursor. FOR i IN (SELECT type_name FROM item_type WHERE UPPER(type_name) = UPPER(item_type_in)) LOOP RETURN i.type_name; END LOOP; END; / |
I hope this answers the question. You can click on the Setup Code line to unfold the code. Let me know if you like this approach to posting setup code.
Setup Code ↓
-- Conditionally drop table and sequence before attempting to create them. BEGIN FOR i IN (SELECT TABLE_NAME FROM user_tables WHERE TABLE_NAME IN (UPPER('item_type') ,UPPER('item'))) LOOP EXECUTE IMMEDIATE 'DROP TABLE '||i.TABLE_NAME||' CASCADE CONSTRAINTS'; END LOOP; FOR i IN (SELECT sequence_name FROM user_sequences WHERE sequence_name IN (UPPER('item_type_s1') ,UPPER('item_s1'))) LOOP EXECUTE IMMEDIATE 'DROP SEQUENCE '||i.sequence_name; END LOOP; END; / -- Create item_type table, index on the natural key, and sequence; then seed data. CREATE TABLE item_type ( item_type_id NUMBER CONSTRAINT pk_item_type PRIMARY KEY , TABLE_NAME VARCHAR2(30) CONSTRAINT nn_item_type_1 NOT NULL , column_name VARCHAR2(30) CONSTRAINT nn_item_type_2 NOT NULL , type_name VARCHAR2(30) CONSTRAINT nn_item_type_3 NOT NULL , code VARCHAR2(5) , meaning VARCHAR2(255) CONSTRAINT nn_item_type_4 NOT NULL); CREATE UNIQUE INDEX item_type_u1 ON item_type(TABLE_NAME,column_name,type_name); CREATE TABLE item ( item_id NUMBER CONSTRAINT pk_item PRIMARY KEY , item_type NUMBER CONSTRAINT nn_item_1 NOT NULL , item_title VARCHAR2(60) CONSTRAINT nn_item_2 NOT NULL , item_rating_id NUMBER CONSTRAINT nn_item_3 NOT NULL); CREATE SEQUENCE item_type_s1 START WITH 1001; CREATE SEQUENCE item_s1 START WITH 1001; INSERT INTO item_type VALUES (item_type_s1.NEXTVAL,'ITEM','ITEM_TYPE','DVD',NULL,'DVD'); INSERT INTO item_type VALUES (item_type_s1.NEXTVAL,'ITEM','ITEM_TYPE','VHS',NULL,'VHS'); INSERT INTO item_type VALUES (item_type_s1.NEXTVAL,'ITEM','ITEM_TYPE','Blu-ray',NULL,'BLRY'); |
very helpful its make cursor more simple.
Thanks
jerry
26 Oct 11 at 1:35 am
Is there a way to add column names dynamically in the where clause for preparing the dynamic cursor.
Thanks.
Naveen
3 Dec 11 at 3:11 am
I think you’re looking for something like this post, but if not let me know.
maclochlainn
5 Dec 11 at 10:50 pm
Replace table name with your table,column name with your column
values in table
guna
sameer
ramesh
Result will be like
guna|sameer|ramesh
Magesh
9 Apr 12 at 5:34 am
Saurabh Sinha
3 Nov 12 at 4:00 am
I’ve no idea why you typed your query in a comment. If you need help with it, try this:
maclochlainn
4 Nov 12 at 12:23 am
[...] blog comment on an NDS statement [...]
Reset START WITH value
22 Nov 12 at 2:03 pm