DB2 iSeries Trigger for added & modified timestamp and user fields - db2

Perhaps triggers are not needed for added/modifed dates, maybe there are appropriate functions to set their values, in any case:
My question is with the following fields,
created (timestamp)
updated (timestamp)
createdBy (string, to hold the created by user name)
updatedBy (string, to hold the updated by user name)
how do I alter the table such that on creation and update these fields hold the appropriate values?
Edit: I now just need to know how to set the updatedBy and updated timestamp fields each time the record is accessed.

Create the following table for a reference:
create table test(
id integer generated always as identity,
content char(60),
createdBy char(30) default user,
created timestamp default current timestamp,
updatedBy char(30),
updated timestamp default null,
primary key(id)
)
This table has an auto incrementing primary key (id), a createdBy field which is set on insert, a created timestamp which is set on insert now we just need triggers to make the last two work as expected (there is a new feature to set updated on update without the use of triggers but the feature does not seem to allow a null value to show the record has never been updated so that does not work for me).
insert into test (content) VALUES ('first thing'),
('second thing')
To see that the default values for created and createdBy have been set:
select * from test
To add update triggers:
CREATE TRIGGER mytrigger
NO CASCADE BEFORE UPDATE ON test
REFERENCING NEW AS post
FOR EACH ROW MODE DB2ROW
SET
post.updated = CURRENT TIMESTAMP,
post.updatedBy = USER
To see if the above is working, lets update the values in "content":
update co05arh/test
set content = 'first thing updated'
where id = 1
To see the new default values
select * from co05arh/test
We should then see something like
ID CONTENT CREATEDBY CREATED UPDATEDBY UPDATED
1 first thing updated KEN 2011-04-29 16:16:17.942429 KEN 2011-04-29 16:16:28.649543
2 second thing KEN 2011-04-29 16:16:18.01629 <null> <null>

Related

PostgreSQL how to build a query which updates data to an existing table but to avoid duplicate value in a specific column

I'm trying to build a very specific PSQL query that has to update a table data adding to a column called sign_order a number that identifies an order of an entity called recipient to sign a document.
To be clear but out of scope is that there is a document that has recipients and the recipients they have to sign that order on a specific order.
I tried initially the following query but the issue is that works if we have no data on the table but soon as it runs on a table filled it generates duplicates for the same type
UPDATE
recipients
SET
sign_order = CASE
"role"
WHEN 'CONSENTEE' THEN 1
WHEN 'GUARDIAN' THEN 2
WHEN 'ASSENTEE' THEN 3
WHEN 'COUNTERSIGNEE' THEN 4
END
WHERE
"role" IN ('CONSENTEE', 'GUARDIAN', 'ASSENTEE', 'COUNTERSIGNEE');
ALTER TABLE recipients ALTER COLUMN sign_order SET NOT NULL;
So what happening here is that is adding the signed order when it finds the case but creates a duplicate for example if that finds already a Guardian it ads as 2 but for the same document we can have multiple Guardian and we have an issue as that is added as Guardian 2 then Guardian 2 but should be Guardian 2 Guardian 3 and so on.
The same affects the rest.
A view of the issue where the recipients under the same document are assigned with the same signing order:
select consentee_id, "role" , count(*)
from recipients
group by "role", consentee_id
order by "count" desc;
Result
The base case order is as in the query;
1 CONSENTEE
2 GUARDIAN
3 ASSENTEE
4 COUNTERSIGNEE
This order needs to be maintained and as an example of the right output running the query should be:
recipient
sign_order
CONSENTEE
1
GUARDIAN
2
GUARDIAN
3
GUARDIAN
4
ASSENTEE
5
COUNTERSIGNEE
6
COUNTERSIGNEE
7
COUNTERSIGNEE
8
I need to add 2 constraints as unique for these consentee_id and sign_order and then make the query more complex to solve the problem described.
The ALTER part I believe with the constraints will look as it is
ALTER TABLE recipients ALTER COLUMN sign_order SET NOT NULL
AND
ADD CONSTRAINT unique_sign_order UNIQUE (consentee_id, sign_order);
However, need some help to achieve the goal of this solving problem issue.
Update to give a better view of the table
Table properties
DDL
CREATE TABLE public.recipients (
id text NOT NULL,
name text NOT NULL,
email text NULL,
phone text NULL,
locale text NULL,
consentee_id text NULL,
is_primary bool NULL DEFAULT false,
sign_order int4 NOT NULL,
"role" text NOT NULL,
created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at timestamptz NULL,
CONSTRAINT recipients_id_unique UNIQUE (id),
CONSTRAINT recipients_pkey PRIMARY KEY (id),
CONSTRAINT recipients_consentee_id_foreign FOREIGN KEY (consentee_id) REFERENCES public.consentees(id) ON DELETE CASCADE
);
Assuming you have some as yet unmentioned unique column (PK perhaps) you can assign the sign_order value in a CTE, then the main portion of the query updates the column for the PK. I've also assumed your table also contains more that 1 document to be signed (if not it a pretty limited table) with its own signing order. In the following these column are id and doc_id respectively. If those assumptions are invalid, well do not know if this will work.
The big change from what you had was to move the CASE expression into an order by clause of a row_number window function. Then assign sort_order from the row_number value and that is a CTE. (see demo)
with assign_sign_order ( rid, sorder) as
( select id, row_number() over (partition by doc_id
order by
case "role"
when 'CONSENTEE' then 1
when 'GUARDIAN' then 2
when 'ASSENTEE' then 3
when 'COUNTERSIGNEE' then 4
end
) so
, "role", doc_id
from recipients order by id
)
update recipients r
set sign_order = s.sorder
from assign_sign_order s
where r.id = s.rid ;
An alternative would be to create a ENUM for the "role", this simplifies the above query, and would reduce maintenance to just updating the ENUM (no change to the query). Providing you do not want to remove one. It is also in the demo.

Why does Id increases by two instead of one using insert

I have been trying to understand after lots of hours and still cannot understand why it is happening.
I have created two tables with ALTER:
CREATE TABLE stores (
id SERIAL PRIMARY KEY,
store_name TEXT
-- add more fields if needed
);
CREATE TABLE products (
id SERIAL,
store_id INTEGER NOT NULL,
title TEXT,
image TEXT,
url TEXT UNIQUE,
added_date timestamp without time zone NOT NULL DEFAULT NOW(),
PRIMARY KEY(id, store_id)
);
ALTER TABLE products
ADD CONSTRAINT "FK_products_stores" FOREIGN KEY ("store_id")
REFERENCES stores (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE RESTRICT;
and everytime I am inserting a value to products by doing
INSERT
INTO
public.products(store_id, title, image, url)
VALUES((SELECT id FROM stores WHERE store_name = 'footish'),
'Teva Flatform Universal Pride',
'https://www.footish.se/sneakers/teva-flatform-universal-pride-t1116376',
'https://www.footish.se/pub_images/large/teva-flatform-universal-pride-t1116376-p77148.jpg?timestamp=1623417840')
I can see that the column of id increases by two everytime I insert instead of one and I would like to know what is the reason behind that?
I have not been able to figure out why and it would be nice to know! :)
There could be 3 reasons:
You've tried to create data but it failed. Even on failed creation and transaction rollback, a sequence does count. A used number will never be put back.
You're using a global sequence and created other data on other data meanwhile. Using a global sequence will always increase on any table data added, even on other tables be modified.
DB configuration for your sequence is set to stepsize/allocationsize=2. It can be configured however you want.
Overall it is not important. The most important thing is that it increases automatically and that even on a error/delete a already tried ID will never be put back.
If you want to have concrete information you need to procive the information about the sequence. You can check that using a SQL CLI or show it via DBeaver/....

Before Update Trigger in Phpmyadmin how to get updated values

I'm trying to get a trigger in phpmyadmin which would create a audit with a certain column value (reputation) before and after the update of a specific table.
Something like:
CREATE DEFINER=`test`#`%`
TRIGGER `monitor update reputation`
BEFORE UPDATE ON `game_resorts`
FOR EACH ROW
INSERT INTO `audit` (`id`, `datetime`, `id_resort`, `reputation`)
VALUES (NULL, CURRENT_TIMESTAMP, id_resort, reputation)
The main question is how can I retrieve the id_resort which will be updated; and then, the reputation value?
In MySQL, you would use the NEW keyword, so I assume it would be the same using phpmyadmin.
For example:
CREATE DEFINER=`test`#`%`
TRIGGER `monitor_update_reputation` //don't use spaces in a trigger name
BEFORE UPDATE ON `game_resorts`
FOR EACH ROW
INSERT INTO `audit` (`datetime`, `id_resort`, `reputation`)
VALUES (CURRENT_TIMESTAMP, NEW.id_resort, NEW.reputation)
If you want to get the value of id_resort or reputation before the update, you can use the OLD keyword:
...
VALUES (CURRENT_TIMESTAMP, OLD.id_resort, OLD.reputation)
Also, I don't think you can insert NULL into a primary key column. If your id on the audit table is set to auto increment, you can simply omit the id column from the INSERT statement.

Created date, last modified date fields in postgress

In PostgreSQL, is there a way to add columns that will automatically record the creation date and latest updated date of a row?
for table creation date look to event triggers
for insertion look into DEFAULT value for timestamptz column (works only if you don't explicitly define value)
for last modification, use trigger FOR EACH ROW before DELETE/UPDATE
The idea - Robust way of adding created and modified fields for data we add to database through db triggers
Update modified_by and modeified_on or modified_at for every db transaction.
Pick created_on and created_by or created_at from modified details whenever you insert a row into tables.
For trigger function, check this repo https://github.com/charan4ks/created_fields.git

Update last modified date column

I have a table like this:
id name modified
11 John 2016-07-12 15:49:45
22 Abraham 2016-07-12 15:52:03
I need to update the 'modified' column which tracks the last modified date for a row. I have done this using a trigger, but have read that triggers eat up performance. Is there a way to do this using constraints?
It's possible to use DEFAULT constraint and DEFAULT keyword in UPDATE clause. See the following example:
CREATE TABLE UpdateTest
(
ID int IDENTITY,
Name varchar(10),
Modified datetime2(2) CONSTRAINT DF_Modified DEFAULT (SYSDATETIME())
)
--ID from IDENTITY, Modified from DEFAULT implicitly
INSERT UpdateTest(Name) VALUES('Test')
--Modified from DEFAULT explicitly
UPDATE UpdateTest SET Name='Test2', Modified=DEFAULT