Home » Developer & Programmer » Forms » forms-mask based on stored procedure ?
forms-mask based on stored procedure ? [message #85213] Wed, 09 June 2004 12:12 Go to next message
hudo
Messages: 165
Registered: May 2004
Senior Member
Hello,

can I base a forms-mask directly on a SELECT-Statement respectively on a stored procedure ?

The following scenario:

CREATE TABLE COL_TABLE
(COL1 VARCHAR2(10),
COL2 VARCHAR2(10),
COL3 VARCHAR2(10),
COL4 DATE,
COL5 NUMBER(4));

INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('AAA','STA1','1',TO_DATE('01.02.2003','dd.mm.yyyy'),1);
INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('AAA','STA1','1',TO_DATE('01.02.2003','dd.mm.yyyy'),60);
INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('AAA','STA1','1',TO_DATE('01.05.2003','dd.mm.yyyy'),1);
INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('AAA','STA1','2',TO_DATE('01.05.2003','dd.mm.yyyy'),50);
INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('AAA','STA1','2',TO_DATE('01.05.2003','dd.mm.yyyy'),1);

INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('AAA','STA2','1',TO_DATE('01.02.2003','dd.mm.yyyy'),1);
INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('AAA','STA2','1',TO_DATE('01.05.2003','dd.mm.yyyy'),1);
INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('AAA','STA2','3',TO_DATE('01.02.2003','dd.mm.yyyy'),40);

INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('AAA','STA3','2',TO_DATE('01.07.2003','dd.mm.yyyy'),1);
INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('AAA','STA3','2',TO_DATE('01.02.2003','dd.mm.yyyy'),1);
INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('AAA','STA3','2',TO_DATE('01.05.2003','dd.mm.yyyy'),1);

INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('BBB','STA1','1',TO_DATE('01.07.2003','dd.mm.yyyy'),11);
INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('BBB','STA1','2',TO_DATE('01.07.2003','dd.mm.yyyy'),5);
INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('BBB','STA1','2',TO_DATE('01.07.2003','dd.mm.yyyy'),1);
INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('BBB','STA1','2',TO_DATE('01.07.2003','dd.mm.yyyy'),12);

INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('BBB','STA3','2',TO_DATE('01.02.2003','dd.mm.yyyy'),1);
INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('BBB','STA3','2',TO_DATE('01.02.2003','dd.mm.yyyy'),5);
INSERT INTO COL_TABLE(COL1,COL2,COL3,COL4,COL5) VALUES('BBB','STA3','2',TO_DATE('01.02.2003','dd.mm.yyyy'),1);

I'd like to perform a mask displaying data based on the following SELECT-statement:

SELECT col1, col2, ok, bad,
ok/total*100 ok_percent, bad/total*100 bad_percent
FROM
(SELECT col1, col2,
SUM(DECODE(col5, 1, 1, 0)) ok,
SUM(DECODE(col5, 1, 0, 1)) bad,
count(*) total
FROM col_table
WHERE col4 BETWEEN TO_DATE('01.02.2003','dd.mm.yyyy') AND TO_DATE('01.07.2003','dd.mm.yyyy')
GROUP BY col1, col2);

The WHERE-clause should be implemented as two forms-text-items for example
start_date and end_date. If start_date and end_date are NULL,
there should be no date-range restriction (no WHERE-clause)
for the SELECT-statement.

My first thought was to create a view based on the SELECT-statement (without the WHERE-clause), because I do not know how to build the view "dynamically" with the date-ranges.
So I think building the mask based directly on the SELECT-statement would be fine.

Maybe there are other possibilities two solve this problem ??

Please help
Re: forms-mask based on stored procedure ? [message #85231 is a reply to message #85213] Thu, 10 June 2004 03:17 Go to previous messageGo to next message
Tak Tang
Messages: 142
Registered: May 2004
Senior Member
hudo,

In future posts, please mention which verion of forms you are using.

What is a 'forms-mask'?

You talk about two different cases for the WHERE clause. In forms 6i, you can set the WHERE clause at runtime using SET_BLOCK_PROPERTY.

Tak
Re: forms-mask based on stored procedure ? [message #85236 is a reply to message #85231] Thu, 10 June 2004 06:50 Go to previous messageGo to next message
hudo
Messages: 165
Registered: May 2004
Senior Member
I used forms 6i. But the masks should be displayed in a normal browser (in conjunction with the Oracle Application Server 10g). So you (Tak) told me that I have to "migrate". That's what I have done. I'm using at the moment both forms 6i and forms 9.0.4.0.19 (from the developer suite 10g)
With forms 9.0.4. I got same difficulties, for example the size of the displayed forms-mask (I call a forms-mask, a mask created with forms displaying the contents of a table for example the scott.emp table, in some way, or what I originally asked in this thread, a mask displaying the result of a SELECT-statement), or attaching a customer menue, although the Forms90Path is set and case-sensitivity is respected.
Back to my problem: I experimented with the example from the forms 6i online help, but I do not get along.
This example is:
/*

This is an example of a stored procedure that returns a ref cursor as a block datasource. A package is used to logically group the related data types and procedures.
*/
PACKAGE cv_datasource IS
TYPE emprec is RECORD (empno emp.empno%TYPE,
ename emp.ename%TYPE,
job emp.job%TYPE,
mgr emp.mgr%TYPE,
sal emp.sal%TYPE,
comm emp.comm%TYPE,
deptno emp.deptno%TYPE);
TYPE empcur is REF CURSOR RETURN emprec;
PROCEDURE empquery(resultset IN OUT empcur,
p_deptno IN NUMBER);
END;

PACKAGE BODY cv_datasource IS
PROCEDURE empquery(resultset IN OUT empcur,
p_deptno IN NUMBER) IS;
BEGIN
OPEN resultset FOR
SELECT empno, ename, job, mgr, sal, comm, deptno
FROM emp
WHERE deptno = p_deptno
ORDER BY empno;
END;
END;

When I start with the Data Block Wizard and choose Stored Procedure, then as Procedure-Name for the query:
cv_datasource.empquery ?, then choose all columns ? and
then there also the fields for entering values for the RESULTSET (Type REFCURSOR) and for P_DEPTNO (Type NUMBER) . What do I have to enter there ?? Continuing with the wizard he asks for an insert-procedure, a delete-procedure and so on. Can someone explain this a little bit more ? It would be great if the explanation would be even with my original example from the top of this thread.

Thanks for your help.
Re: forms-mask based on stored procedure ? [message #85239 is a reply to message #85236] Thu, 10 June 2004 09:24 Go to previous messageGo to next message
Tak Tang
Messages: 142
Registered: May 2004
Senior Member
In forms 6i, you can base a block on a select statement. You need to create the block manually; set the data source to 'from clause', and in the 'FROM' box, enter a SELECT statement in brackets.

eg (select ename, length(ename) as ename_length from emp)

This would give you two fields - ename and ename_length.

To implement the varying WHERE clause, I would use SET_BLOCK_PROPERTY just before executing the query, or maybe have a static where clause with NVL() to deal with a blank date range.

For basing a block on a REF CURSOR, I'll try to explain why Forms is asking for procedures. Normally, Forms creates blocks based on database tables, and automatically provides functionality to insert, update and delete records. A REF CURSOR however, can not be updated - you cannot issue DML against a ref cursor. So forms expects you to create procedures which do inserts, updates and deletes.

Here is a sample I got from a book :-

CREATE OR REPLACE
PACKAGE empdept_maint
AS
/******************************************************************************
|| System:     SPMTS
||
|| Description: 
||   Procedures used for an EMP-DEPT block query source and target.
||
|| Usage:
||   SLCT
||      Queries all records from the EMP-DEPT table join
|| 
||   INS
||      Inserts a record in the EMP-DEPT table.
||
||   UPD
||      Updates a record as specified by the empno parameter passed in.
||
||   DEL
||      Deletes the record specified by the empno parametere passed in.
||
||   LCK
||      Locks the record specified by the empno parametere passed in.
||      
******************************************************************************/
   TYPE emp_t IS RECORD(
      empno     emp.empno%TYPE,
      job       emp.job%TYPE,
      hiredate  emp.hiredate%TYPE,
      deptno    dept.deptno%TYPE,
      dname     dept.dname%TYPE);

   -- For SELECT
   TYPE rc_empdept IS REF CURSOR 
      RETURN emp_t;

   -- For the DML - a table of records
   TYPE t_empdept 
      IS TABLE OF emp_t 
      INDEX BY BINARY_INTEGER;
   --
   PROCEDURE slct( 
      p_empqry IN OUT rc_empdept);
   --
   PROCEDURE ins(
      p_emprec IN OUT t_empdept);
   --
   PROCEDURE upd(
      p_emprec IN OUT t_empdept);
   --
   PROCEDURE del(
      p_emprec IN OUT t_empdept);
   --
   PROCEDURE lck(
      p_emprec IN OUT t_empdept);
   --
END;
/

CREATE OR REPLACE
PACKAGE BODY empdept_maint 
AS

/*
||   Private procedures
*/
   FUNCTION dept_not_exists(
      p_dept_num  NUMBER)
      RETURN BOOLEAN
   IS
      CURSOR c_dept (
         p_dept dept.deptno%TYPE)
      IS
         SELECT 1
         FROM   dept
         WHERE  deptno = p_dept;
      --
      v_dummy    dept.deptno%TYPE;
      v_return   BOOLEAN;
   BEGIN
      OPEN c_dept(p_dept_num);
      FETCH c_dept INTO v_dummy;
      v_return := c_dept%NOTFOUND;
      CLOSE c_dept;
      RETURN v_return;
   END;

/*
||   Public procedures
*/
   PROCEDURE slct( 
      p_empqry IN OUT rc_empdept)
   IS
   BEGIN
      -- This can be more complex and include conditional
      -- logic to select from one source or another.
      OPEN p_empqry
      FOR
         SELECT emp.empno, 
                emp.job, 
                emp.hiredate, 
                emp.deptno, 
                dept.dname
         FROM   emp emp, dept dept
         WHERE  emp.deptno = dept.deptno;
   END;
--
--
   PROCEDURE ins(
      p_emprec IN OUT t_empdept)
   IS
      v_message  VARCHAR2(100);
   BEGIN
      FOR v_ct IN 1 .. p_emprec.count
      LOOP
         -- If the dept doesn't exist, insert it
         IF p_emprec(v_ct).deptno IS NOT NULL
         THEN
            IF dept_not_exists(p_emprec(v_ct).deptno)
            THEN
               v_message:= 'Insert of DEPT';
               INSERT INTO dept(
                       deptno, 
                       dname)
               VALUES (p_emprec(v_ct).deptno, 
                       p_emprec(v_ct).dname);
               -- exception handling goes here. This might even be a separate
               -- procedure to do the insert.
               -- 
            END IF;
            --
            v_message := 'Insert of EMP';
            INSERT INTO emp(
               empno,
               job,
               hiredate,
               deptno)
            VALUES (
               p_emprec(v_ct).empno, 
               p_emprec(v_ct).job, 
               p_emprec(v_ct).hiredate,
               p_emprec(v_ct).deptno);
            -- add an exception handler here
         END IF;
      END LOOP;
   EXCEPTION
      WHEN OTHERS
      THEN
         raise_application_error(-20002, 'Error: Inserting record using ' ||
            'EMPDEPT_MAINT.INS. Inform Technical Support. '|| v_message);
   END;
--
--
   PROCEDURE upd(
      p_emprec IN OUT t_empdept)
   IS
      v_message   VARCHAR2(200);
   BEGIN
      -- update the records from the table of records
      -- check the dept table first
      -- You could also update the DEPT record with the values 
      -- in the DEPT columns
      -- For this exercise, just update the EMP columns
      FOR v_ct IN 1 .. p_emprec.count
      LOOP
         IF dept_not_exists(p_emprec(v_ct).deptno)
         THEN
            v_message:= 'Insert of DEPT';
            INSERT INTO dept(
                   deptno, 
                   dname)
            VALUES (p_emprec(v_ct).deptno, 
                    p_emprec(v_ct).dname);
            -- exception handling goes here. This might even be a separate
            -- procedure to do the insert.
            -- 
         END IF;
         --
         UPDATE emp
         SET    job = p_emprec(v_ct).job,
                hiredate = p_emprec(v_ct).hiredate,
                deptno = p_emprec(v_ct).deptno
         WHERE  empno = p_emprec(v_ct).empno;
      END LOOP;
   END;
--
--
   PROCEDURE del(
      p_emprec IN OUT t_empdept)
   IS
   BEGIN
      FOR v_ct IN 1 .. p_emprec.count
      LOOP
         DELETE FROM emp 
         WHERE  empno = p_emprec(v_ct).empno;
      END LOOP;
   END;

   PROCEDURE lck(
      p_emprec IN OUT t_empdept)
   IS
      v_empno    emp.empno%TYPE;
   BEGIN
      FOR v_ct IN 1 .. p_emprec.count
      LOOP
         SELECT empno
         INTO   v_empno
         FROM   emp
         WHERE  empno = p_emprec(v_ct).empno
         FOR UPDATE;
      END LOOP;
   END;

END;
/

You can down load this, and other code from :-
http://ourworld.compuserve.com/homepages/Peter_Koletzke/Utilities/advdev.zip
Re: forms-mask based on stored procedure ? [message #85259 is a reply to message #85239] Fri, 11 June 2004 05:45 Go to previous messageGo to next message
hudo
Messages: 165
Registered: May 2004
Senior Member
@Tak: Thanks for the example, it works. I also implemented a "negative" example containing just the empdept_maint.slct procedure, then inserting or updating the table is not possible.

But I got some problems with the following:
-----
In forms 6i, you can base a block on a select statement. You need to create the block manually; set the data source to 'from clause', and in the 'FROM' box, enter a SELECT statement in brackets.

eg (select ename, length(ename) as ename_length from emp)

This would give you two fields - ename and ename_length.

To implement the varying WHERE clause, I would use SET_BLOCK_PROPERTY just before executing the query, or maybe have a static where clause with NVL() to deal with a blank date range.
----

I "Build a new data block manually". On the Block-Level Property-Palette:
Database->Database Data Block: Yes
Database->Query Data Source Type: FROM clause query
Database->Query Data Source Name: (select ename, length(ename) as ename_length from emp)

Then I build the two text items:
ENAME :
DATA->DataType: Char
Database->Database Item : ????
Database->Column Name: ???

ENAME_LENGTH :
Data->DataType:Number
Database->Database Item : ????
Database->Column Name: ???

By starting a query in Forms an error occurs:
FRM-41003: This function cannot by performed here

(because I tried to perform a function referencing a table, but the block does not correspond to any table)

Please help
Re: forms-mask based on stored procedure ? [message #85263 is a reply to message #85259] Fri, 11 June 2004 13:27 Go to previous messageGo to next message
Tak Tang
Messages: 142
Registered: May 2004
Senior Member
Consider this :-
CREATE VIEW emp_v AS
SELECT ename, LENGTH(ename) AS ename_length
FROM emp
/

You could select from this view, just as if it was a table.
SELECT v.ename, v.ename_length
FROM emp_v v
ORDER BY v.ename
/

Or I could write the view 'inline' like this :-
SELECT v.ename, v.ename_length
FROM ( SELECT ename, LENGTH(ename) AS ename_length FROM emp ) v
ORDER BY v.ename
/

You could also create a database block based on emp_v, exactly as if it was a table, or you could write the view 'inline'.

Does this explain enough for you to answer your own question?

Tak
Re: forms-mask based on stored procedure ? [message #85265 is a reply to message #85259] Fri, 11 June 2004 14:42 Go to previous messageGo to next message
hudo
Messages: 165
Registered: May 2004
Senior Member
No, not really. This was not my question.
Actually my problem is the IMPLEMENTATION of a query that is not based on a table nor a view but directly on a FROM-clause query (as you mentioned somewhere in this thread and is also indicated in the forms online-help).
Consider "its not allowed" for the developer to create views or even tables on the server, so he can query a stored procedure or use a FROM-clause query. But with the implementation of the last I got my problems:

I "Build a new data block manually". On the Block-Level Property-Palette:
Database->Database Data Block: Yes
Database->Query Data Source Type: FROM clause query
Database->Query Data Source Name: (select ename, length(ename) as ename_length from emp)
Database->Query Database Source Columns:
ENAME with Type VARCHAR2 and Length 10
ENAME_LENGTH with Type Number and Precision 2

Is this correct so far ??

Then I build the two text items:
NAME :
Data->DataType: Char
Database->Database Item : Yes
Database->Column Name: ENAME

LENG :
Data->DataType:Number
Database->Database Item : Yes
Database->Column Name: ENAME_LENGTH

Correct ??

But by starting a query in Forms an error occurs:
FRM-41003: This function cannot by performed here

Thanks for your advice and patience
Re: forms-mask based on stored procedure ? [message #178363 is a reply to message #85239] Tue, 20 June 2006 16:25 Go to previous message
zsiddiquis
Messages: 4
Registered: June 2006
Location: Mississauga Canada
Junior Member
Hi Gurus,
Eveything is going fine with this package but i found some problem whenever i update the and commit record then i wanted to execute query but form is stuck.

Any help will be appreciate.

Regards
Zeeshan

CREATE OR REPLACE PACKAGE empdept_maint
AS
-- Purpose :
--
-- Created By : Zeeshan Hussain Siddiqui
-- Creation Date : 20-06-2006
-- Last Updated BY : Zeeshan Hussain Siddiqui
-- Last Updataed On : 20-06-2006
-------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------

TYPE emp_t IS RECORD(
empno emp.empno%TYPE,
job emp.job%TYPE,
hiredate emp.hiredate%TYPE,
deptno dept.deptno%TYPE,
dname dept.dname%TYPE);
-- For SELECT
TYPE rc_empdept IS REF CURSOR
RETURN emp_t;
-- For the DML - a table of records
TYPE t_empdept
IS TABLE OF emp_t
INDEX BY BINARY_INTEGER;
--
PROCEDURE slct(
p_empqry IN OUT rc_empdept);

FUNCTION dept_not_exists(p_dept_num NUMBER)
RETURN BOOLEAN;
--
PROCEDURE ins(
p_emprec IN OUT t_empdept);
--
PROCEDURE upd(
p_emprec IN OUT t_empdept);
--
PROCEDURE lck(
p_emprec IN OUT t_empdept);

PROCEDURE del(
p_emprec IN OUT t_empdept);
--

--
END empdept_maint;
/
CREATE OR REPLACE PACKAGE BODY empdept_maint
AS
-- Purpose :
--
-- Created By : Zeeshan Hussain Siddiqui
-- Creation Date : 20-06-2006
-- Last Updated BY : Zeeshan Hussain Siddiqui
-- Last Updataed On : 20-06-2006
-------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------
PROCEDURE slct(
p_empqry IN OUT rc_empdept)
IS
BEGIN
-- This can be more complex and include conditional
-- logic to select from one source or another.
OPEN p_empqry
FOR
SELECT emp.empno,
emp.job,
emp.hiredate,
emp.deptno,
dept.dname
FROM emp emp, dept dept
WHERE emp.deptno = dept.deptno;
END slct;
-----------------------------------------------------------------------
FUNCTION dept_not_exists(
p_dept_num NUMBER)
RETURN BOOLEAN
IS
CURSOR c_dept (
p_dept dept.deptno%TYPE)
IS
SELECT 1
FROM dept
WHERE deptno = p_dept;
--
v_dummy dept.deptno%TYPE;
v_return BOOLEAN;
BEGIN
OPEN c_dept(p_dept_num);
FETCH c_dept INTO v_dummy;
v_return := c_dept%notfound;
CLOSE c_dept;
RETURN v_return;
END dept_not_exists;
-----------------------------------------------------------------------
PROCEDURE ins(
p_emprec IN OUT t_empdept)
IS
v_message VARCHAR2(100);
BEGIN
FOR v_ct IN 1 .. p_emprec.count
LOOP
-- If the dept doesn't exist, insert it
IF p_emprec(v_ct).deptno IS NOT NULL
THEN
IF dept_not_exists(p_emprec(v_ct).deptno)
THEN
v_message:= 'Insert of DEPT';
INSERT INTO dept(
deptno,
dname)
VALUES (p_emprec(v_ct).deptno,
p_emprec(v_ct).dname);
-- Exception handling goes here.
END IF;
--
v_message := 'Insert of EMP';
INSERT INTO emp(
empno,
job,
hiredate,
deptno)
VALUES (
p_emprec(v_ct).empno,
p_emprec(v_ct).job,
p_emprec(v_ct).hiredate,
p_emprec(v_ct).deptno);
-- add an exception handler here
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS
THEN
raise_application_error(-20002, 'Error: Inserting record ' ||
'using EMPDEPT_MAINT.INS. Inform Technical Support. '|| v_message);
END ins;
----------------------------------------------------------------------------------------------
PROCEDURE upd(
p_emprec IN OUT t_empdept)
IS
v_message VARCHAR2(200);
BEGIN
-- update the records from the table of records
-- check the dept table first
-- You could also update the DEPT record with the values
-- in the DEPT columns
-- For this exercise, just update the EMP columns
FOR v_ct IN 1 .. p_emprec.count
LOOP
IF dept_not_exists(p_emprec(v_ct).deptno)
THEN
v_message:= 'Insert of DEPT';
INSERT INTO dept(
deptno,
dname)
VALUES (p_emprec(v_ct).deptno,
p_emprec(v_ct).dname);
-- exception handling goes here. This might even be a separate
-- procedure to do the insert.
--
END IF;
--
UPDATE emp
SET job = p_emprec(v_ct).job,
hiredate = p_emprec(v_ct).hiredate,
deptno = p_emprec(v_ct).deptno
WHERE empno = p_emprec(v_ct).empno;
END LOOP;
END upd;
----------------------------------------------------------------------------------------------
PROCEDURE lck(
p_emprec IN OUT t_empdept)
IS
v_empno emp.empno%TYPE;
BEGIN
FOR v_ct IN 1 .. p_emprec.count
LOOP
SELECT empno
INTO v_empno
FROM emp
WHERE empno = p_emprec(v_ct).empno
FOR UPDATE;
END LOOP;
END lck;
----------------------------------------------------------------------------------------------
PROCEDURE del(
p_emprec IN OUT t_empdept)
IS
BEGIN
FOR v_ct IN 1 .. p_emprec.count
LOOP
DELETE FROM emp
WHERE empno = p_emprec(v_ct).empno;
END LOOP;
END del;


END empdept_maint ;
/
Previous Topic: go_record; go_item
Next Topic: how to insert records from a text file into a table
Goto Forum:
  


Current Time: Fri Sep 20 09:39:52 CDT 2024