DEV Community

Super Kai (Kazuya Ito)
Super Kai (Kazuya Ito)

Posted on • Edited on

FOR statement in PostgreSQL

Buy Me a Coffee

A FOR statement:

*My post explains LOOP, EXIT, CONTINUE and WHILE statement.

Now, you can create the PL/pgSQL function my_func() with the FOR statement whose range is 1..3 and a LOOP statement as shown below:

CREATE FUNCTION my_func() RETURNS VOID
AS $$
BEGIN
  FOR num IN 1..3 LOOP
    RAISE INFO '%', num;
  END LOOP;
END
$$ LANGUAGE plpgsql;
Enter fullscreen mode Exit fullscreen mode

*Memos:

  • You don't need declare num local variable in a DECLARE clause but you can if you want

  • My post explains a PL/pgSQL function.

  • A RAISE statement can raise an error or message.

Then, calling my_func() raises 3 messages in the loop, then exits the loop when the iteration of the last value 3 is finished as shown below:

postgres=# SELECT my_func();
INFO:  1
INFO:  2
INFO:  3
 my_func
---------

(1 row)
Enter fullscreen mode Exit fullscreen mode

Next, you can use REVERSE with the FOR statement whose range is 3..1 as shown below. *Be careful, if the range is 1..3, no messages are raised:

CREATE FUNCTION my_func() RETURNS VOID
AS $$
BEGIN
  FOR num IN REVERSE 3..1 LOOP
    RAISE INFO '%', num;
  END LOOP;
END
$$ LANGUAGE plpgsql;
Enter fullscreen mode Exit fullscreen mode

Then, calling my_func() raises 3 messages in the loop, then exits the loop when the iteration of the last value 1 is finished as shown below:

postgres=# SELECT my_func();
INFO:  3
INFO:  2
INFO:  1
 my_func
---------

(1 row)
Enter fullscreen mode Exit fullscreen mode

Next, you can use a BY clause with the FOR statement whose range is 1..5 as shown below:

CREATE FUNCTION my_func() RETURNS VOID
AS $$
BEGIN
  FOR num IN 1..5 BY 2 LOOP
    RAISE INFO '%', num;
  END LOOP;
END
$$ LANGUAGE plpgsql;
Enter fullscreen mode Exit fullscreen mode

Then, calling my_func() raises 3 messages in the loop by 2 steps, then exits the loop when the iteration of the last value 5 is finished as shown below:

postgres=# SELECT my_func();
INFO:  1
INFO:  3
INFO:  5
 my_func
---------

(1 row)
Enter fullscreen mode Exit fullscreen mode

Next, you can use the inner and outer FOR statements whose ranges are 3..3 and 1..2 respectively as shown below:

CREATE FUNCTION my_func() RETURNS VOID
AS $$
BEGIN
  FOR num IN 3..3 LOOP
    FOR num IN 1..2 LOOP
      RAISE INFO 'Inner loop:%', num;
    END LOOP;
    RAISE INFO 'Outer loop:%', num;
  END LOOP;
END
$$ LANGUAGE plpgsql;
Enter fullscreen mode Exit fullscreen mode

Then, calling my_func() raises 3 messages in the inner and outer loops, then exits the loop when the iterations of the last values 2 and 3 are finished respectively as shown below:

postgres=# SELECT my_func();
INFO:  Inner loop:1
INFO:  Inner loop:2
INFO:  Outer loop:3
 my_func
---------

(1 row)
Enter fullscreen mode Exit fullscreen mode

Next, you create person table as shown below:

CREATE TABLE person (
  id INT,
  name VARCHAR(20),
  age INT
);
Enter fullscreen mode Exit fullscreen mode

Then, you insert 4 rows into person table as shown below:

INSERT INTO person (id, name, age) 
VALUES (1, 'John', 27), (2, 'David', 32), (3, 'Robert', 18), (4, 'Mark', 40);
Enter fullscreen mode Exit fullscreen mode

Then, you can use the FOR statement with a SELECT statement as shown below:

CREATE FUNCTION my_func(min INT, max INT) RETURNS VOID
AS $$
DECLARE
  row RECORD;
BEGIN
  FOR row IN SELECT * FROM person WHERE age BETWEEN min AND max LOOP
    RAISE INFO '%', row;
  END LOOP;
END
$$ LANGUAGE plpgsql;
Enter fullscreen mode Exit fullscreen mode

*Memos:

  • You must declare row local variable in a DECLARE clause otherwise there is the error.

  • You cannot use REVERSE with the FOR statement which has SQL otherwise there is error so instead, you can use ORDER BY id DESC for the SELECT statement.

  • You cannot use a BY clause with the FOR statement which has SQL otherwise there is error so instead, you can use WHERE mod(id, 2) = 1 for the SELECT statement. *The doc explains mod() in detail.

  • You cannot use a SELECT INTO statement with a FOR statement otherwise there is the error(7).

  • My post has the examples of a FOR statement with a RETURN NEXT statement.

Or, you can use the FOR statement with an EXECUTE statement which has a SELECT statement as shown below:

CREATE FUNCTION my_func(min INT, max INT) RETURNS VOID
AS $$
DECLARE
  row RECORD;
BEGIN
  FOR row IN EXECUTE 'SELECT * FROM person WHERE age BETWEEN $1 AND $2' USING min, max LOOP
    RAISE INFO '%', row;
  END LOOP;
END
$$ LANGUAGE plpgsql;
Enter fullscreen mode Exit fullscreen mode

Then, calling my_func() raises 2 messages in the loop, then exits the loop when the iteration of the last row is finished as shown below:

postgres=# SELECT my_func(30, 40);
INFO:  (2,David,32)
INFO:  (4,Mark,40)
 my_func
---------

(1 row)
Enter fullscreen mode Exit fullscreen mode

Next, you can use the FOR statement with a UPDATE statement as shown below. *You must set a RETURNING clause to the UPDATE statement with a FOR statement otherwise there is error:

CREATE FUNCTION my_func(my_age INT, my_id INT) RETURNS VOID
AS $$
DECLARE
  row RECORD;
BEGIN
  FOR row IN UPDATE person SET age = my_age WHERE id = my_id RETURNING * LOOP
    RAISE INFO '%', row;
  END LOOP;
END
$$ LANGUAGE plpgsql;
Enter fullscreen mode Exit fullscreen mode

Or, you can use the FOR statement with an EXECUTE statement which has a UPDATE statement as shown below:

CREATE FUNCTION my_func(my_age INT, my_id INT) RETURNS VOID
AS $$
DECLARE
  row RECORD;
BEGIN
  FOR row IN EXECUTE 'UPDATE person SET age = $1 WHERE id = $2 RETURNING *' USING my_age, my_id LOOP
    RAISE INFO '%', row;
  END LOOP;
END
$$ LANGUAGE plpgsql;
Enter fullscreen mode Exit fullscreen mode

Then, it raises a message in the loop, then exits the loop when the iteration of the last row is finished as shown below:

postgres=# SELECT my_func(75, 2);
INFO:  (2,David,75)
 my_func
---------

(1 row)
Enter fullscreen mode Exit fullscreen mode

Then, age of David is updated to 75 as shown below:

postgres=# SELECT * FROM person;
 id |  name  | age
----+--------+-----
  1 | John   |  27
  3 | Robert |  18
  4 | Mark   |  40
  2 | David  |  75
(4 rows)
Enter fullscreen mode Exit fullscreen mode

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more