php - 跳过修改 CTE 并返回现有键而不是插入新键(如果值已存在)
问题描述
我正在 PostgreSQL 中编写一个查询,我在我的 php 代码中使用该查询,用户应该能够通过输入演员名称将演员添加到演员列表中。我正在使用修改 CTE 来执行此操作,因为它需要更新数据库中的三个表:
- Person(Person_ID:Serial, Name: Varchar,... 其他不相关的信息,可以留空)
- Personnel(Personnel_ID:Serial, Role: Varchar, Person_ID:Int (FK)) FilmPeople(Personnel_ID (FK), Media_ID (FK))
- 所以actor作为一个人在person表中,然后连接到personal中的一个角色,然后这个角色连接到一个media_ID。
到目前为止的查询:
WITH person_cte AS (
INSERT INTO Person(Name)
SELECT :actorname
WHERE NOT EXISTS (
SELECT 1 FROM person WHERE name = :actorname2)
RETURNING person_id
),
personnel_cte AS (
INSERT INTO Personnel(role, person_id)
SELECT 'Actor', person_id FROM person_cte
RETURNING personnel_id
)
INSERT INTO FilmPeople(Personnel_ID, Media_ID)
SELECT personnel_id, :id from personnel_cte¨
所以你们可能看到的问题是,到目前为止,我的查询仅在数据库中根本不存在参与者时才有效。如果在 Person 表中找到演员,它将失败。我真正想要的是如果演员亲自存在,那么不要插入任何东西,而是将已经存在的 person_id 返回到下一个 cte。然后同样的事情,如果该演员的人员(角色)已经存在,则继续使用personal_id,仅将演员添加到最后一个表以将他/她连接到电影。然后即使在这里,如果它已经存在,那么不要做任何事情。
编辑:这是现在创建表的方式:
CREATE TABLE Person(
Person_ID serial,
Name varchar(255),
DateOfBirth date,
Gender varchar(45),
CONSTRAINT PK_Person PRIMARY KEY (Person_ID)
);
CREATE TABLE Personnel(
Personnel_ID serial,
Role varchar(255),
Person_ID bigint,
CONSTRAINT PK_Personnel PRIMARY KEY (Personnel_ID),
CONSTRAINT FK_PersonPersonnel FOREIGN KEY (Person_ID)
REFERENCES Person(Person_ID)
);
CREATE TABLE FilmPeople(
Personnel_ID bigint,
Media_ID int,
CONSTRAINT PK_FilmPeople PRIMARY KEY (Personnel_ID, Media_ID),
CONSTRAINT FK_PersonnelFilmPeople FOREIGN KEY (Personnel_ID)
REFERENCES Personnel(Personnel_ID),
CONSTRAINT FK_MediaFilmPeople FOREIGN KEY (Media_ID)
REFERENCES Media(Media_ID)
);
解决方案
当没有插入任何内容时,该returning
子句返回为空 - 所以这不是您想要的方法。相反,我会建议加入表格。为了使其正常工作,我强烈建议在每个表上使用唯一键,如下所示:
person(name)
personnel(role,person_id)
filmpeople(personnel_id, media_id)
然后你可以使用on conflict
:
with
person_cte as (
insert into person(name)
values (:actorname)
on conflict (name) do nothing
),
personnel_cte as (
insert into personnel(role, person_id)
select 'actor', p.person_id
from person p
where p.name = :actorname
on conflict (role, person_id) do nothing
)
insert into filmpeople(personnel_id, media_id)
select personnel_id, :id
from pl.personnel pl
inner person p on p.person_id = pl.person_id
where p.name = :actorname and pl.role = 'actor'
on conflict (personnel_id, media_id) do nothing
推荐阅读
- javascript - 考虑到时区变化,通过 date-fns 添加一天
- android - 如何解决 Manifest 合并失败错误
- flutter - 在我的颤振应用程序中集成语音命令输入的好方法是什么?
- ionic-framework - cordova-plugin-admob-free 不适用于 cordova-plugin-firebase
- haskell - 在haskell中为monads创建一个过滤函数
- r - 有没有办法根据列中的因子循环数据并加起来行数?
- git - 为什么我要登录这么多次?
- tensorflow - Tensorflow 2.0:已保存模型中的变量
- database - 从 firebase 数据库中检索数据作为 hashmap 的值,并使用 react native 显示键和值
- java - java.lang.ClassCastException:java.util.LinkedHashMap 在尝试对列表进行排序时无法转换为 java.lang.Comparable 异常