Reputation: 4373
I'm trying to munge data from a few columns across a few tables to make it full-text searchable, but I'm not having much luck.
Here's my function:
CREATE OR REPLACE FUNCTION on_customer_save_udpate_tsv() RETURNS trigger AS $$
declare
tsv_text text;
begin
SELECT string_agg(cust_text.text, ' ') as agg_text into tsv_text
FROM (SELECT concat("name", ' ', "phone") as text
FROM "Customers"
where "id" = NEW.id
UNION
SELECT concat("firstName", ' ', "lastName", ' ', "phone", ' ', "email") as text
FROM "Contacts"
where "customerId" = NEW.id
UNION
SELECT concat("streetLine1", ' ', "city", ' ', "state", ' ', "zip") as text
FROM "Addresses"
where "customerId" = NEW.id) cust_text;
NEW.tsv := to_tsvector(coalesce(tsv_text,''));
return NEW;
end
$$ LANGUAGE plpgsql;
Here's my trigger:
CREATE TRIGGER cust_tsv_trigger BEFORE INSERT OR UPDATE
ON "Customers" FOR EACH ROW EXECUTE PROCEDURE on_customer_save_udpate_tsv();
However, the "Customers".tsv column is blank after inserts/updates.
When I run the bulk of the function manually, it works as expected.
DO $$
declare
tsv_text text;
begin
SELECT string_agg(cust_text.text, ' ') as agg_text into tsv_text
FROM (SELECT concat("name", ' ', "phone") as text
FROM "Customers"
where "id" = 17
UNION
SELECT concat("firstName", ' ', "lastName", ' ', "phone", ' ', "email") as text
FROM "Contacts"
where "customerId" = 17
UNION
SELECT concat("streetLine1", ' ', "city", ' ', "state", ' ', "zip") as text
FROM "Addresses"
where "customerId" = 17) cust_text;
UPDATE "Customers"
SET tsv = to_tsvector(coalesce(tsv_text, ''))
WHERE "id" = 17;
end
$$ LANGUAGE plpgsql;
I'm fairly new to postgres. What am I missing?
Upvotes: 2
Views: 969
Reputation: 61676
As the trigger runs BEFORE INSERT or UPDATE, having it select from the table to get the new values is flawed, because the new values are not there already.
Consider this part of the query:
SELECT concat("name", ' ', "phone") as text
FROM "Customers"
where "id" = NEW.id
In the case of an INSERT, you'll always get NULL here and in the case of an UPDATE, you'll get the values that are about to be replaced rather than the new ones.
What should be used as a drop-in replacement for the code above is:
SELECT (NEW.name || ' ' || NEW.phone) AS text
Another point that looks suspicious is: if any of the fields in the user details from any of the 3 tables is NULL, then the whole concatened contents are going to be empty, because the code applies coalesce
at the very end instead of doing it on each individual field.
Upvotes: 2