I'm using Postgres 12.2.
I try to fill a kind of event table where I have one column which needs to get the id of something.
In the example I created, the events are stored in the purchases table while the id needs to be the id of the company, taken from the companies table. As there is no fixed set of companies, the companies table needs to "grow as I go" ;).
So the setup is:
CREATE TABLE
companies
(
company_id SERIAL NOT NULL,
NAME CHARACTER VARYING(256) NOT NULL,
PRIMARY KEY (company_id),
CONSTRAINT companies_unique_name UNIQUE (NAME)
)
;
CREATE TABLE
purchases
(
purchase_id SERIAL NOT NULL,
purchase_date DATE DEFAULT CURRENT_DATE NOT NULL,
amount INTEGER NOT NULL,
company_id INTEGER NOT NULL,
PRIMARY KEY (purchase_id)
)
;
So when I now want to insert the event "Purchased 5 items from 'company1'", I need to get the id of "company1" by either looking it up in the companies table or by creating a new entry for "company1" in companies.
I can do it like this:
WITH EXISTING_COMPANY AS (
SELECT company_id FROM companies WHERE name = 'company1'
)
, NEW_COMPANY AS (
INSERT INTO companies (name) VALUES ('company1')
ON CONFLICT(name) DO NOTHING
RETURNING company_id
)
, GET_COMPANY_ID AS (
SELECT COALESCE(
(SELECT company_id FROM EXISTING_COMPANY),
(SELECT company_id FROM NEW_COMPANY)
) AS company_id
)
INSERT INTO purchases(amount, company_id)
VALUES (5, (select company_id from GET_COMPANY_ID))
;
The CTE EXISTING_COMPANY will give me the id of an existing "company1" or null.
The CTE NEW_COMPANY will give me the id of a newly created company "company1" or null
The CTE GET_COMPANY_ID finally will, by using coalesce, try to get an existing id and, if that fails, a new id.
While this works it has the disadvantages that I need to give the company name twice and that I need new CTEs for each company as I do not know how to pass the company name to my CTEs.
- Is there a way how to pass the company name to my CTEs?
- Are there other ways to achieve my goal?