Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the loginizer domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /home/despjszs/public_html/wp-includes/functions.php on line 6114
PostgreSQL : Write a function to iterate over the rows of a table and Update the Data – Despina Papatheodorou

PostgreSQL : Write a function to iterate over the rows of a table and Update the Data


Assume that you have a table where Subscriptions are stored, example given you have bought a new Spotify subscription, for 3, 6 or 12 months.

In this table , the data that are kept are :

  • the creation date (created_at)
  • last update timestamp (last_updated)
  • start_date of Subscription
  • start_date of Subscription
  • end_date of Subscription
  • duration_in_months (3,6 or 12)
  • customer_id , the customer that bought the subscription

/** Create the table*/
create table subscriptions
(
    id     serial PRIMARY KEY,
    created_at       timestamp,
    last_updated     timestamp,
    start_date       timestamp,
    end_date         timestamp,
    duration_in_months integer,
    customer_id     varchar(255)

);


Let’s feed the table with data

INSERT INTO subscriptions ( created_at, last_updated, start_date, end_date,duration_in_months, customer_id)
VALUES ( NOW(), NOW(), '2022-05-19' ,null,  3, 'customer-1');

INSERT INTO subscriptions ( created_at, last_updated, start_date, end_date, duration_in_months, customer_id)
VALUES ( NOW(), NOW(), '2022-05-19' ,null,  6, 'customer-2');


Problem to Solve:

We want to create a function to iterate over the rows of this table , check the subscription duration and update the end_date column

create or replace function update_dates() returns void
    language plpgsql
AS
$$
DECLARE
    t_curs cursor for
        SELECT *
        FROM subscriptions
        WHERE start_date IS NOT NULL
          AND duration_in_months IS NOT NULL;
    t_row     subscriptions%rowtype;
    _end_date timestamp;

BEGIN

    FOR t_row in t_curs
        LOOP

            RAISE NOTICE 'id: %', t_row.id;
            RAISE NOTICE 'duration_in_months: %', t_row.duration_in_months;
            RAISE NOTICE 'start_date %' , t_row.start_date;

            CASE t_row.duration_in_months
                WHEN 3 THEN _end_date = t_row.start_date + interval '3 months';
                WHEN 6 THEN _end_date = t_row.start_date + interval '3 months';
                WHEN 12 THEN _end_date = t_row.start_date + interval '6 months';
                ELSE _end_date = NULL;
                END CASE;

            RAISE NOTICE '_new_end_date %', _end_date;

            IF _end_date IS NOT NULL THEN
                update subscriptions
                set end_date     = _end_date,
                    last_updated = NOW()
                where current of t_curs;

                RAISE NOTICE 'update subscription with ID  % ', t_row.id;
            END IF;

        END LOOP;
END
$$;

Let’s start explain:

DECLARE
    t_curs cursor for
        SELECT *
        FROM subscriptions
        WHERE start_date IS NOT NULL
          AND duration_in_months IS NOT NULL;
    t_row     subscriptions%rowtype;

Creates a cursor over table subscriptions , for the rows that have start_date and duration_in_months columns not null

 FOR t_row in t_curs
        LOOP
.....
END LOOP;

Creates a loop and iterate over the selected rows of the table

CASE t_row.duration_in_months
                WHEN 3 THEN _end_date = t_row.start_date + interval '3 months';
                WHEN 6 THEN _end_date = t_row.start_date + interval '3 months';
                WHEN 12 THEN _end_date = t_row.start_date + interval '6 months';
                ELSE _end_date = NULL;
                END CASE;

Applies a case selection, based of the value of duration_in_months column for each row, it computes and set value to _end_date variable

 update subscriptions
                set end_date     = _end_date,
                    last_updated = NOW()
                where current of t_curs;

Update the row , with the commuted values

RAISE NOTICE 'update subscription with ID  % ', t_row.id;

RAISE NOTICE is used to print on console

Magic time… execute the function

select update_dates();

The console logs:

your_database_name> select update_dates()
[2022-05-17 23:01:14] [00000] id: 1

[2022-05-17 23:01:14] [00000] duration_in_months: 3
[2022-05-17 23:01:14] [00000] start_date 2022-05-19 00:00:00
[2022-05-17 23:01:14] [00000] _new_end_date 2022-08-19 00:00:00
[2022-05-17 23:01:14] [00000] update subscription with ID  1
[2022-05-17 23:01:14] [00000] id: 2
[2022-05-17 23:01:14] [00000] duration_in_months: 6
[2022-05-17 23:01:14] [00000] start_date 2022-05-19 00:00:00
[2022-05-17 23:01:14] [00000] _new_end_date 2022-08-19 00:00:00
[2022-05-17 23:01:14] [00000] update subscription with ID  2
[2022-05-17 23:01:14] 1 row retrieved starting from 1 in 33 ms (execution: 7 ms, fetching: 26 ms)
ciab.public> select * from subscriptions
[2022-05-17 23:01:21] 2 rows retrieved starting from 1 in 45 ms (execution: 2 ms, fetching: 43 ms)

And then , verify:

select * from subscriptions;