postgresql - CTE中的Postgres SELECT或INSERT?
问题描述
我正在使用 Postgres 12.2。
我尝试填写一种事件表,其中有一列需要获取某物的 id。
在我创建的示例中,事件存储在purchases
表中,而 id 需要是公司的 id,取自companies
表。由于没有固定的公司集,因此公司表需要“随我增长”;)。
所以设置是:
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)
)
;
因此,当我现在想要插入事件“Purchased 5 items from 'company1'”时,我需要通过在companies
表中查找“company1”或通过在companies
.
我可以这样做:
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))
;
CTEEXISTING_COMPANY
将为我提供现有“company1”或null
.
CTENEW_COMPANY
会给我一个新创建的公司“company1”的 id 或null
CTEGET_COMPANY_ID
最终将通过使用coalesce
尝试获取现有 id,如果失败,则获取新 id。
虽然这可行,但它的缺点是我需要两次提供公司名称,并且我需要为每家公司提供新的 CTE,因为我不知道如何将公司名称传递给我的 CTE。
- 有没有办法将公司名称传递给我的 CTE?
- 还有其他方法可以实现我的目标吗?
解决方案
您可以为新名称提供values()
另一个 CTE 中的子句。您也不需要existing_company
CTE,因为这也可以在get_company
cte 内完成:
WITH input(name) as (
values ('company1')
), new_company AS (
INSERT INTO companies (name)
select i.name
from input i
ON CONFLICT (name) DO NOTHING
RETURNING company_id
), get_company_id AS (
select company_id
from new_company
union all
select company_id
from companies
where name in (select name from input)
and not exists (select * from new_company)
)
INSERT INTO purchases(amount, company_id)
select 5, company_id
from get_company_id
;
这也可以扩展到处理多个公司和金额:
WITH input(amount, name) as (
values
(5, 'company1'),
(6, 'company2')
), new_company AS (
INSERT INTO companies (name)
select name
from input
ON CONFLICT (name) DO NOTHING
RETURNING company_id, name
), get_company_id AS (
select company_id, name
from new_company
union all
select c.company_id, c.name
from companies c
where c.name in (select i.name from input i)
and not exists (select *
from new_company nc
where nc.company_id = c.company_id)
)
INSERT INTO purchases(amount, company_id)
select i.amount, g.company_id
from get_company_id g
join input i on i.name = g.name
;
推荐阅读
- typescript - 打字稿:返回有关参数值的多种类型
- graphics - 如何读取 Vulkan 中的模板缓冲区?
- .net - .NET 中的 TLS - 第三方根 CA 未被识别为受信任的根 CA
- c# - 过滤列表并删除不需要的数据 C#
- plot - gnuplot 矩阵热图图翻转
- clojure - Clojure 空序列行为
- swift - 需要按两次取消按钮才能转到上一个视图控制器
- javascript - 创建 Photoshop 插件 - 尝试在 javascript 函数中找到更简单的源文件方法
- javascript - 导出数组 ReactJS - 错误:数组是只读的
- javascript - 如何将字符串数组复制到对象中