0

I am begginer in PL/SQL and I want to create function to retrive AllProject. SO far what I create is

          CREATE OR REPLACE FUNCTION GETALLPROJECTS(currentUserID in INT)
   RETURN SYS_REFCURSOR
IS 
   rc  SYS_REFCURSOR;
BEGIN
OPEN rc FOR
        SELECT p.*
        FROM projects p
        LEFT JOIN project_users_schedule_dates pusd
ON     
      pusd.ProjectID = p.ProjectID
AND 
      pusd.UserID = currentUserID
LEFT JOIN responsible_persons rp
ON
   rp.ProjectID = p.ProjectID
AND 
   rp.UserID = currentUserID
LEFT JOIN users u ON u.UserID = currentUserID
WHERE    
     u.User_roleID = 1
(
    (p.Responsible_person_id = currentUserId OR 
    p.Delivery_contact = currentUserId OR 
    rp.UserID = currentUserId OR 
    (pusd.ProjectID = p.ProjectID AND                         
    pusd.UserID = currentUserId AND NOW() BETWEEN pusd.StartDate AND pusd.EndDate + INTERVAL 1 DAY 
    AND
    NOW() BETWEEN p.StartDate AND p.EndDate + INTERVAL 1 DAY)
    AND p.status = 2)
)
 ORDER BY p.ProjectID;
RETURN rc;
END GETALLPROJECTS;

When I compile I gett two error which I dont understand what errors are:

First error is:

Error(6,1): PL/SQL: SQL Statement ignored

And Second error is:

Error(27,24): PL/SQL: ORA-00933: SQL command not properly ended
  • Also please check if the query is working independently outside the function, I see problem with Group by statement as well. – Atif Aug 07 '20 at 09:22
  • Yes I test it and it works fine, but when I convert it to function doesnt work ! –  Aug 07 '20 at 09:27
  • This looks a bit odd `u.User_roleID = 1 ( (p.Responsible_person_id = currentUserId OR..` Are you sure this SQL works? – Scratte Aug 07 '20 at 11:58
  • This is `MySQL` query which I need to transfer to `PL/SQL` –  Aug 07 '20 at 12:14

2 Answers2

1

A superfluous comma, should be = instead of :=, missing semi-colon, missing single quotes for INTERVAL.

Also, you can't select that many columns into a single VARCHAR2 variable, nor can you GROUP BY a single column. Consider returning a ref cursor instead:

CREATE OR REPLACE FUNCTION GETALLPROJECTS (currentUserID IN INT)
   RETURN SYS_REFCURSOR
IS
   rc  SYS_REFCURSOR;
BEGIN
   OPEN rc FOR
        SELECT p.*
          FROM projects p
               LEFT JOIN project_users_schedule_dates pusd
                  ON     pusd.ProjectID = p.ProjectID
                     AND pusd.UserID = currentUserID
               LEFT JOIN responsible_persons rp
                  ON     rp.ProjectID = p.ProjectID
                     AND rp.UserID = currentUserID
               LEFT JOIN users u ON u.UserID = currentUserID
         WHERE    u.User_roleID = 1
               OR ( (   p.Responsible_person_id = currentUserID
                     OR p.Delivery_contact = currentUserID
                     OR rp.UserID = currentUserID
                     OR     (    pusd.ProjectID = p.ProjectID
                             AND pusd.UserID = currentUserID
                             AND NOW () BETWEEN pusd.StartDate
                                            AND pusd.EndDate + INTERVAL '1' DAY
                             AND NOW () BETWEEN p.StartDate
                                            AND p.EndDate + INTERVAL '1' DAY)
                        AND p.status = 2))
      ORDER BY p.ProjectID;

   RETURN rc;
END GETALLPROJECTS;

As I don't have your tables, here's a example created on Scott's sample schema, just to illustrate what you might have done:

SQL> create or replace function getallemp (par_deptno in number)
  2    return sys_refcursor
  3  is
  4    rc sys_refcursor;
  5  begin
  6    open rc for
  7      select e.*
  8      from emp e
  9      where e.deptno = par_deptno
 10      order by e.ename;
 11    return rc;
 12  end;
 13  /

Function created.

SQL>
SQL> select getallemp(10) from dual;

GETALLEMP(10)
--------------------
CURSOR STATEMENT : 1

CURSOR STATEMENT : 1

     EMPNO ENAME      JOB              MGR HIREDATE        SAL       COMM     DEPTNO
---------- ---------- --------- ---------- -------- ---------- ---------- ----------
      7782 CLARK      MANAGER         7839 09.06.81       2450                    10
      7839 KING       PRESIDENT            17.11.81      10000                    10
      7934 MILLER     CLERK           7782 23.01.82       1300                    10


SQL>
Littlefoot
  • 131,892
  • 15
  • 35
  • 57
  • still have a problem. Error: PL/SQL: Compilation unit analysis terminated Error(1,29): PLS-00201: identifier 'CURRENTUSERID' must be declared –  Aug 07 '20 at 08:40
  • Should be `CREATE OR REPLACE FUNCTION GETALLPROJECTS (currentUserID in int)`, not vice versa. – Littlefoot Aug 07 '20 at 09:16
  • I have no idea what happened here, but still have errors :/ –  Aug 07 '20 at 09:23
  • I added some more info as well as an example. See if it helps. – Littlefoot Aug 07 '20 at 09:30
  • That's the main problem. I want to speed up my application which is done in PHP and Oracle database. Some query use INNER JOIN two or more table. I am in problem right now because I have no idea what to do since Functions are slower. –  Aug 07 '20 at 09:37
  • I don't know PHP, but - as far as Oracle is concerned, if there are several tables involved, the simplest way of *performance tuning* is to create indexes on columns involved in joins. That *usually* helps, not doesn't have to as everything depends on current situation. You should gather statistics on those tables (and indexes), check what explain plan says, etc. Performance tuning itself is a *large chapter*, can't be done in a few lines of text. But, won't cost much to try doing what I said. – Littlefoot Aug 07 '20 at 09:43
  • In these situation, can I use `CURSOR` to retrive more then one column or whatelse ? Since I am begginer in Oracle and PL/SQL and I don't have enought skills and knowlegde but from my perspektiv of views best idea is use store procedure nor functions. Since I read that functions are slower then StoreProcedure. However, thank you for you suggestions and time and also for helps :) –  Aug 07 '20 at 09:49
  • Ummm ... where did you read that? If both function and a procedure use the same code (i.e. the SELECT statement), why would one be slower than another? As of a cursor: sure, you can use it, but cursors usually mean *loops* and loops process data row-by-row which is usually much slower than working with whole sets of data. – Littlefoot Aug 07 '20 at 10:27
  • You can see here https://stackoverflow.com/questions/1942753/performance-difference-between-user-defined-function-and-stored-procedures#:~:text=Stored%20Procedures%20can%20be%20fast,as%20they%20are%20pre%2Dcompiled.&text=A%20Stored%20Procedure%20will%20return,result)%20or%20return%20Tabular%20data. –  Aug 07 '20 at 10:33
  • Although it is related to MS SQL Server database (not Oracle), I agree with what Remus had said. Key point is "so is really apple to oranges" - procedures and functions should be used for different purposes. If you're *processing* something (inserting into tables, updating them, ...), use a procedure. Yes, it can *return* the result using its OUT parameter(s), but - if you're about to *return* values, then use functions. Procedures can't be used in SQL (you need PL/SQL), functions can. Functions can't do DML, procedures can. Once again: apples to oranges. – Littlefoot Aug 07 '20 at 10:47
0

Use this query and first check if query is working independently by passing the hardcoded value in the query:

CREATE OR REPLACE FUNCTION GETALLPROJECTS(currentUserID in INT)
   RETURN SYS_REFCURSOR
IS 
   rc  SYS_REFCURSOR;
BEGIN
OPEN rc FOR
        SELECT p.ProjectID,
            p.CustomName,
            p.Name,
            p.Responsible_person_id,
            p.Delivery_contact,
            p.StartDate,
            p.EndDate,
            p.TehnicReview,
            p.status
        FROM projects p
        LEFT JOIN project_users_schedule_dates pusd
ON     
      pusd.ProjectID = p.ProjectID
AND 
      pusd.UserID = currentUserID
LEFT JOIN responsible_persons rp
ON
   rp.ProjectID = p.ProjectID
AND 
   rp.UserID = currentUserID
LEFT JOIN users u ON u.UserID = currentUserID
WHERE    
     u.User_roleID = 1
(
    (p.Responsible_person_id = currentUserId OR 
    p.Delivery_contact = currentUserId OR 
    rp.UserID = currentUserId OR 
    (pusd.ProjectID = p.ProjectID AND                         
    pusd.UserID = currentUserId AND NOW() BETWEEN pusd.StartDate AND pusd.EndDate + INTERVAL 1 DAY 
    AND
    NOW() BETWEEN p.StartDate AND p.EndDate + INTERVAL 1 DAY)
    AND p.status = 2)
)
 ORDER BY p.ProjectID;
RETURN rc;
END GETALLPROJECTS;
Atif
  • 2,011
  • 9
  • 23
  • Hmmm ... No sure what you mean –  Aug 07 '20 at 09:26
  • You mean one variable one column ? –  Aug 07 '20 at 09:29
  • Yes, if you selecting 10 columns you need to have 10 variables but if want to return single value then use that column in the select and have one variable to store that value. – Atif Aug 07 '20 at 09:46
  • Can you please provide some example –  Aug 07 '20 at 09:50
  • Please specify your requirement which values you want to return from the query, one single column or multiple columns, @LITTLEFOOT already shared an example that if more than one column needs to be retruned then you have to make use of ref cursor. Please specify your requirement. – Atif Aug 07 '20 at 09:59
  • I need to retrive multiple column p.ProjectID, p.CustomName, p.Name, p.Responsible_person_id, p.Delivery_contact, p.StartDate, p.EndDate, p.TehnicReview, p.status These column needs to be retrive –  Aug 07 '20 at 10:02
  • Then make use of ref cursor in the example above. If you still struggle with that then let me know. I will share complete code. – Atif Aug 07 '20 at 10:06
  • Yes I stuck over here. Still have error. I update my question with new code –  Aug 07 '20 at 10:07
  • Just avoid use `SELECT * statment`. Use only column which I specify in comment above –  Aug 07 '20 at 10:09
  • Interesting think, when I pass hardcoded value it works, but when I move to function doesnt work –  Aug 07 '20 at 10:46
  • Share the error message when running the updated code. – Atif Aug 07 '20 at 10:47
  • `Error(32,30): PL/SQL: ORA-00907: missing right parenthesis` `Error(7,9): PL/SQL: SQL Statement ignored` –  Aug 07 '20 at 10:54
  • Error(32,30): PL/SQL: ORA-00907: missing right parenthesis AND is missing after u.User_roleID = 1 – Atif Aug 07 '20 at 11:12
  • Are you sure you are using Oracle because now() function is in MYSQL. – Atif Aug 07 '20 at 11:15
  • Yes, this query is transfer from MySQL to Oracle. I just now see that NOW() function. –  Aug 07 '20 at 11:21
  • How to convert these to PLSQL sintax `pusd.UserID = currentUserId AND NOW() BETWEEN pusd.StartDate AND pusd.EndDate + INTERVAL 1 DAY AND NOW() BETWEEN p.StartDate AND p.EndDate + INTERVAL 1 DAY)` –  Aug 07 '20 at 11:24
  • You can google and will get equivalent for NOW() in Oracle sysdate is used and if you want to add one day to p.enddate then write p.enddate + 1 – Atif Aug 07 '20 at 11:27
  • Yes, you were right. NOW() is `sysdate` in Oracle PLSQL. But currently the problem is here `AND pusd.EndDate + 1 AND sysdate BETWEEN p.StartDate` –  Aug 07 '20 at 11:41
  • I would suggest to explain the business logic so please edit your question because this is actually a conversion of query from MYSQL to ORACLE. – Atif Aug 07 '20 at 12:23