【问题标题】:Do nothing on foreign key violation in SQL insert query对 SQL 插入查询中的外键违规不执行任何操作
【发布时间】:2021-07-27 15:14:16
【问题描述】:

在迁移程序中,我对 table_1 执行插入查询,其定义如下:

CREATE TABLE table_1
(
    col1 character varying(4)  COLLATE pg_catalog."default" NOT NULL,
    col2 character varying(10) COLLATE pg_catalog."default" NOT NULL,
    col3 character varying(10) COLLATE pg_catalog."default" NOT NULL,
    col4 character varying(40) COLLATE pg_catalog."default" NOT NULL,
    col5 date NOT NULL,
    col6 date NOT NULL,

    CONSTRAINT table_1_pkey 
        PRIMARY KEY (col1, col2, col3, col4, col5, col6),

    CONSTRAINT table_2_fkey FOREIGN KEY (col4)
        REFERENCES table_2 (col1) MATCH SIMPLE
            ON UPDATE NO ACTION
            ON DELETE NO ACTION,
    CONSTRAINT table_3_fkey FOREIGN KEY (col3)
        REFERENCES table_3(col1) MATCH SIMPLE
            ON UPDATE NO ACTION
            ON DELETE NO ACTION
            NOT VALID
)
WITH (
    OIDS = FALSE
)
TABLESPACE pg_default;

现在当我尝试插入此表时,我收到此错误:

事务错误中的错误:在表“table_1”上插入或更新违反了外键约束“table_2_fkey”

我尝试以这种形式进行插入查询:

INSERT INTO table_1(col1, col2, col3, col4, col5, col6) 
VALUES 
(col1_value1, col2_value1, col3_value1, col4_value1, col5_value1, col6_value1),
(col1_value2, col2_value2, col3_value2, col4_value2, col5_value2, col6_value2),
(col1_value3, col2_value3, col3_value3, col4_value3, col5_value3, col6_value3)
ON CONFLICT (col1, col2, col3, col4, col5, col6) DO NOTHING;

有没有办法防止违反外键约束(跳过它们)?

类似ON VIOLATION DO NOTHING

注意:它不违反第二个外键约束,因为我用我尝试填充到 table_1 的行来填充这个表 (table_2) 中的数据(用于规范化)。 table_2 是一个早先存在的表,我在另一个程序中填充了那里的行,所以那里可能缺少数据,我想跳过向 table_1 插入与 table_2 的外键不匹配的行。

使用 PostgreSQL 10.16,由 Visual C++ build 1800 编译,64 位

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    没有违反约束的“什么都不做”选项。您可以在 table_2 中创建一个虚拟字段,这样当父表中的值无法匹配时,它可以在 table_2 中引用某些内容(排序的占位符值)。

    或者,您可以改用映射表来删除外键约束。这样,您可以决定映射表是否应该插入新记录。这不太可能是实现您的设计目标的最佳方式。

    table_1
        id
        ...  other data fields ...
    
    table_2
        id
        ...  other data fields ...
    
    map_table
        id
        table1_id (FK)
        table2_id (FK)
    

    【讨论】:

    • 我会选择第二种解决方案,问题是我不决定我的设计将如何。对于第一个解决方案,当值不可用时,我不能使用占位符,因为它让我回到了问题:我如何告诉 sql 做某事\在发生违规时获取一些值?
    • 第二种情况没有违规。您正在进行两次插入,插入 table_1,然后如果 table_2 中有值,则可以插入 map_table。这必须是业务逻辑决策,而不是 sql 语句 (imo)
    • 我绝对同意你的观点,第二种方法可以解决它。虽然,它不能满足我的需求。对于第一个解决方案,如果 table_2 中存在值并且如果不取占位符,我如何检查插入查询?此外,这不是我正在寻找的解决方案,如果 table_2 中不存在该值,我想跳过并且不向 table_1 插入一行。
    【解决方案2】:

    我使用了来自此answer 的查询的变体。感谢@_horse_with_no_name

    这是对我有用的查询:

    with data_table(col1, col2, col3, col4,
                    col5, col6) as (
        values
            ('value1','','1','num1','1900-01-01'::date, '9999-12-31'::date),
            ('value2','','1','num2','1900-01-01'::date, '9999-12-31'::date)   
    )
    insert into table_1(col1, col2, col3,
                        col4, col5, col6)
    select d.col1, d.col2, d.col3, d.col4,
           d.col5, d.col6
    from data_table d
    where exists (select 1
                  from table_2 t2
                  where t2.col1 = d.col4)
    on conflict(col1, col2, col3, col4, col5, col6) do nothing;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-20
      • 1970-01-01
      • 2011-11-28
      • 1970-01-01
      • 2019-01-17
      • 1970-01-01
      • 2015-04-11
      相关资源
      最近更新 更多