Can I make a postgres table automagically concatenate itself into a single row? π§ Letβs find out.
Donβt try this in production
Create a schema/table to play with:
stan=> create schema questionable;
CREATE SCHEMA
stan=> set search_path to questionable ;
SET
stan=> create table demo(t text);
CREATE TABLE
Create a function that uses a temporary table to collect aggregated rows and reinsert them as a single row after emptying the table:
CREATE OR REPLACE FUNCTION tf_concatenate_rows()
RETURNS TRIGGER AS $TF$
BEGIN
IF (SELECT count(*) FROM demo) > 1 THEN
CREATE TEMPORARY TABLE _squeeze(t TEXT);
INSERT INTO _squeeze SELECT string_agg(t, E'\n') FROM demo;
DELETE FROM demo;
INSERT INTO demo SELECT * FROM _squeeze;
DROP TABLE _squeeze;
END IF;
RETURN NEW;
END;
$TF$ LANGUAGE plpgsql;
See PostgreSQL Documentation: Triggers, Trigger Functions.
Create the table trigger:
CREATE TRIGGER concatenate_rows AFTER INSERT ON demo
EXECUTE FUNCTION tf_concatenate_rows();
Letβs see what this bad boy can do:
stan=> insert into demo select 'insert first row';
INSERT 0 1
stan=> table demo;
t
ββββββββββββββββββ
insert first row
(1 row)
stan=> insert into demo select 'insert 2nd row';
INSERT 0 1
stan=> table demo;
t
ββββββββββββββββββ
insert first rowβ΅
insert 2nd row
(1 row)
stan=> insert into demo values ('this'), ('is'), ('a'), ('bad'), ('idea?');
INSERT 0 5
stan=> table demo;
t
ββββββββββββββββββ
insert first rowβ΅
insert 2nd row β΅
this β΅
is β΅
a β΅
bad β΅
idea?
(1 row)
π
Of course, I had a semi-useful purpose for trying this, concatenating multi-line JSON objects into a single line.
stan=> truncate demo;
TRUNCATE TABLE
stan=> \copy demo from stdin csv quote e'\x01' delimiter e'\x02'
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself, or an EOF signal.
>> {
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}>> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >>
>> \.
COPY 22
stan=> table demo;
t
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
{ β΅
"glossary": { β΅
"title": "example glossary", β΅
"GlossDiv": { β΅
"title": "S", β΅
"GlossList": { β΅
"GlossEntry": { β΅
"ID": "SGML", β΅
"SortAs": "SGML", β΅
"GlossTerm": "Standard Generalized Markup Language", β΅
"Acronym": "SGML", β΅
"Abbrev": "ISO 8879:1986", β΅
"GlossDef": { β΅
"para": "A meta-markup language, used to create markup languages such as DocBook.",β΅
"GlossSeeAlso": ["GML", "XML"] β΅
}, β΅
"GlossSee": "markup" β΅
} β΅
} β΅
} β΅
} β΅
}
(1 row)
It works, but it is more complicated than using a query in a view or procedure. No real gain here; I just wanted to see if was possible.