0

I'm using PostgreSQL and have an employee table:

employeeid | FirstName | LastName | Department | Position
    1      | Aaaa      |          |            |
    2      | Bbbb      |          |            |
    3      |           |          |            |
    .      |           |          |            |

Reports table:

employeeid |        enter        |        exit
     1     | 2020-11-08 09:02:21 | 2020-11-08 18:12:01
     .     |         ...         |                     

Now, I'm querying for missed employees on a certain date something like that function:

for i in select employeeid from employee
loop
    if select not exists(select 1 from reports where enter::date = '2020-11-08' and employeeid = i) then
       return query select employeeid, lastname, firstname, department, position from employee where employeeid = i;        
    end if;
end loop; 

Seems to me, it's not an ideal solution. Is there any better approach to achieve the same result? Thanks.

1
  • If you have a new question, then ask a new question (possibly linking back to this one). Don't extend your existing one Commented Nov 9, 2020 at 7:16

2 Answers 2

2

Your code is pretty non effective. Probably it cannot be written badly :-). The reply @a_horse_with_no_name is absolutely correct, just for completeness I'll fix your plpgsql code.

DECLARE _e employee;
BEGIN
  FOR _e IN SELECT * FROM employee
  LOOP
    IF NOT EXISTS(SELECT * 
                    FROM reports r
                   WHERE r.enter::date = date '2020-11-08'
                     AND r.employeeid = _e.employeeid)
    THEN
      RETURN NEXT _e;
    END IF;
  END LOOP;
END;

When you write stored procedure (or any query based application), the important value is number of queries - low number is better (attention - there are exceptions - sometimes too much complex queries can be slower due their complexity). In your example there are employees * 2 + 1 queries (with larger overhead of plpgsql - RETURN QUERY is more expensive than RETURN NEXT). Solution proposed by @a_horse_with_no_name is one query (without a overhead of plpgsql). Any my example has employees + 1 queries (with lower overhead of plpgsql).

Your example is good example of one common SQL antipattern - "using ISAM style".

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for the deep explanation. One more question: how about if I need results in the period of the time? For example From=2020-11-0, To=2020-11-08. And result employeeid, lastname, firstname, department, position, misseddate
@Ma'ruf - it is not a problem just you can use BETWEEN operator instead =. When the result of query has not same structure like your expected result, then you can use a custom composite type. Almost all is possible - plpgsql and SQL are mature languages. Please, start by plpgsql documentation reading - it has less 50 pages, and you will see all possibilities - postgresql.org/docs/current/plpgsql.html
how about misseddate column in the return table? Now I'm updating my question.
The identifiers in RETURNS TABLE(...) are OUT variables too. So you can fill these variables and use RETURN NEXT without arguments, or you can use composite value in REURN NEXT like RETURN NEXT (r.employeeid, r. ..., _f_from_date).
so is that the correct way of looping through date ranges? _res = f_to - f_from; for i in 0.._res loop _from = f_from + i;
|
0

You are right: more often than not, a loop is a bad way to do things in a relational database.

You can do this in plain SQL:

select e.employeeid, e.lastname, e.firstname, e.department, e.position 
from employee e
where not exists (select *
                  from reports r
                  where r.enter::date = date '2020-11-08'
                    and e.employeeid = r.employeeid);

This will return all employees for which no row exists in the reports table on 2020-11-08

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.