SqlLite - SQLite 中带有级联删除的外键?

问题描述 投票:0回答:1

我尝试在子表上使用外键,并在从父表中删除行时收到错误。这是我对Cascade删除的理解。 使用级联删除

具有级联删除功能的外键意味着如果父级中的记录 表被删除,那么子表中对应的记录 会自动删除。这称为级联删除 SQLite。

具有级联删除功能的外键只能在 CREATE 中定义 TABLE 语句。

提示:您不能使用级联删除将外键添加到表中 ALTER TABLE 因为 SQLite 不支持 ADD CONSTRAINT ALTER TABLE 语句。不过,我们稍后会向您展示解决方法 本教程将允许您使用级联添加外键 删除到现有表。

这是我的父表的 DDL。

CREATE TABLE Astro_Target_Imaged (
    ATI_TargetName                TEXT     NOT NULL,
    ATI_Telescope                 TEXT     NOT NULL,
    ATI_FocalLength               TEXT     NOT NULL,
    ATI_SITELONG                  TEXT     NOT NULL,
    ATI_SITELAT                   TEXT     NOT NULL,
    ATI_ICAMERA                   TEXT,
    ATI_ROTNAME                   TEXT,
    ATI_ROTATOR                   TEXT,
    ATI_FWHEEL                    TEXT,
    ATI_FOCNAME                   TEXT,
    ATI_GCAMERA                   TEXT,
    ATI_GSCOPE,
    ATI_Location_Name             TEXT,
    ATI_DataFolder_Location       TEXT,
    ATI_Posted_FinalProcessed_URL TEXT,
    ATI_Bortle                    TEXT (1),
    ATI_Archived                  TEXT (1) DEFAULT N,
    ATI_ArchiveFolderLocation     TEXT,
    ATI_DateAdded                 TEXT,
    ATI_DateLastUpdated           TEXT,
    PRIMARY KEY (
        ATI_TargetName,
        ATI_Telescope,
        ATI_FocalLength,
        ATI_SITELONG,
        ATI_SITELAT
    )
);

这是我应用级联和外键的子表。

CREATE TABLE Astro_Target_Imaged_Date (
    ATI_TargetName          TEXT        NOT NULL
                                        REFERENCES Astro_Target_Imaged (ATI_TargetName) ON DELETE CASCADE,
    ATI_Telescope           TEXT        NOT NULL
                                        REFERENCES Astro_Target_Imaged (ATI_Telescope) ON DELETE CASCADE,
    ATI_FocalLength         TEXT        NOT NULL
                                        REFERENCES Astro_Target_Imaged (ATI_FocalLength) ON DELETE CASCADE,
    ATID_CCYYMMDD           TEXT        NOT NULL,
    ATI_SITELONG            TEXT        NOT NULL
                                        REFERENCES Astro_Target_Imaged (ATI_SITELONG) ON DELETE CASCADE,
    ATI_SITELAT             TEXT        REFERENCES Astro_Target_Imaged (ATI_SITELAT) ON DELETE CASCADE,
    TZ_UTC_Offset           INTEGER (2),
    MI_Illumination_Percent TEXT,
    PRIMARY KEY (
        ATI_TargetName,
        ATI_Telescope,
        ATI_FocalLength,
        ATID_CCYYMMDD,
        ATI_SITELONG,
        ATI_SITELAT
    )
);

错误信息:

[10:45:08] 从表 Astro_Target_Imaged 中删除行时出错: 外键不匹配 - “Astro_Target_Imaged_Date”引用 “Astro_Target_Imaged”

我没有看到名字不匹配,但我可能正在看过去。

sqlite
1个回答
0
投票

根据评论,是的,如果应用,应该可以解决问题。

即外键中指定的父级必须能够引用唯一行(如果存在),而不是潜在的多行。

因此,每个 FKEY 定义必须存在一个 UNQIUE 索引(如果是主键则隐式存在)或通过 UNIQUE 索引显式存在。

在您的情况下,需要 5 个这样的索引,但它们都不存在。然而,您可能想反映父母的独特性。那就是有一个复合的外键定义。

复合外键定义不能在列级别定义,因此必须在表级别定义为约束,语法为:-

https://www.sqlite.org/syntax/table-constraint.html

看来您想要:-

CREATE TABLE IF NOT EXISTS Astro_Target_Imaged_Date (
    ATI_TargetName          TEXT        NOT NULL
                                        -- REFERENCES Astro_Target_Imaged (ATI_TargetName) ON DELETE CASCADE
                                        ,
    ATI_Telescope           TEXT        NOT NULL
                                        -- REFERENCES Astro_Target_Imaged (ATI_Telescope) ON DELETE CASCADE
                                        ,
    ATI_FocalLength         TEXT        NOT NULL
                                        -- REFERENCES Astro_Target_Imaged (ATI_FocalLength) ON DELETE CASCADE
                                        ,
    ATID_CCYYMMDD           TEXT        NOT NULL,
    ATI_SITELONG            TEXT        NOT NULL
                                        -- REFERENCES Astro_Target_Imaged (ATI_SITELONG) ON DELETE CASCADE
                                        ,
    ATI_SITELAT             TEXT        -- REFERENCES Astro_Target_Imaged (ATI_SITELAT) ON DELETE CASCADE
                                        ,
    
    TZ_UTC_Offset           INTEGER (2),
    MI_Illumination_Percent TEXT,
    PRIMARY KEY (
        ATI_TargetName,
        ATI_Telescope,
        ATI_FocalLength,
        ATID_CCYYMMDD,
        ATI_SITELONG,
        ATI_SITELAT
    ),
    FOREIGN KEY (ATI_TargetName,ATI_Telescope,ATI_FocalLength,ATI_SITELONG,ATI_SITELAT)
        REFERENCES Astro_Target_Imaged (ATI_TargetName,ATI_Telescope,ATI_FocalLength,ATI_SITELONG,ATI_SITELAT)
        ON DELETE CASCADE ON UPDATE CASCADE
);
  • note注释掉了原来的列级FKEY定义
  • note 添加了演示更新:-

使用您的代码,按上述修改,然后:-

INSERT INTO Astro_Target_Imaged
    VALUES ('T1','TEL1','F1','SLON1','SLAT200','CAM1','RNAME1','ROR1','W1','FNAME1','GCAM1','GSCOPE1','LOC1','DLOC1','URL1','BORTLE1','ARCY','ARCF1','2024-01-01','2024-01-01')
    ,('T2','TEL1','F1','SLON1','SLAT200','CAM1','RNAME1','ROR1','W1','FNAME1','GCAM1','GSCOPE1','LOC1','DLOC1','URL1','BORTLE1','ARCY','ARCF1','2024-01-01','2024-01-01')
    ,('T3','TEL1','F1','SLON1','SLAT200','CAM1','RNAME1','ROR1','W1','FNAME1','GCAM1','GSCOPE1','LOC1','DLOC1','URL1','BORTLE1','ARCY','ARCF1','2024-01-01','2024-01-01')
    ,('T4','TEL1','F1','SLON1','SLAT200','CAM1','RNAME1','ROR1','W1','FNAME1','GCAM1','GSCOPE1','LOC1','DLOC1','URL1','BORTLE1','ARCY','ARCF1','2024-01-01','2024-01-01')
    ,('T5','TEL2','F1','SLON1','SLAT200','CAM1','RNAME1','ROR1','W1','FNAME1','GCAM1','GSCOPE1','LOC1','DLOC1','URL1','BORTLE1','ARCY','ARCF1','2024-01-01','2024-01-01')
    ,('T6','TEL2','F1','SLON1','SLAT200','CAM1','RNAME1','ROR1','W1','FNAME1','GCAM1','GSCOPE1','LOC1','DLOC1','URL1','BORTLE1','ARCY','ARCF1','2024-01-01','2024-01-01')
    ,('T7','TEL2','F1','SLON1','SLAT200','CAM1','RNAME1','ROR1','W1','FNAME1','GCAM1','GSCOPE1','LOC1','DLOC1','URL1','BORTLE1','ARCY','ARCF1','2024-01-01','2024-01-01')
;
INSERT OR IGNORE INTO Astro_Target_Imaged_Date
    VALUES ('T1','TEL1','F1','2024-01-01','SLON1','SLAT200',10,50)
    ,('T1','TEL1','F1','2024-01-02','SLON1','SLAT200',10,50)
    ,('T1','TEL1','F1','2024-01-03','SLON1','SLAT200',10,50)
    ,('T2','TEL1','F1','2024-01-03','SLON1','SLAT200',10,50)
    ,('T2','TEL1','F1','2024-01-04','SLON1','SLAT200',10,50)
    ,('T3','TEL1','F1','2024-01-01','SLON1','SLAT200',10,50)
    ,('T3','TEL1','F1','2024-01-02','SLON1','SLAT200',10,50)
    ,('T3','TEL1','F1','2024-01-03','SLON1','SLAT200',10,50)
    ,('T5','TEL2','F1','2024-01-01','SLON1','SLAT200',10,50)
    ,('T5','TEL2','F1','2024-01-02','SLON1','SLAT200',10,50)
;
;
SELECT a.ati_targetname, a.ati_telescope,b.atid_ccyymmdd,*  FROM astro_target_imaged AS a JOIN astro_target_imaged_date AS b 
    ON a.ati_targetname = b.ati_targetname
    AND a.ati_telescope = b.ati_telescope
    AND a.ati_focallength = b.ati_focallength
    AND a.ati_sitelong = b.ati_sitelong
    AND a.ati_sitelat = b.ati_sitelat
;
DELETE FROM astro_target_imaged WHERE ati_targetname = 'T1';
SELECT a.ati_targetname, a.ati_telescope,b.atid_ccyymmdd,*  FROM astro_target_imaged AS a JOIN astro_target_imaged_date AS b 
    ON a.ati_targetname = b.ati_targetname
    AND a.ati_telescope = b.ati_telescope
    AND a.ati_focallength = b.ati_focallength
    AND a.ati_sitelong = b.ati_sitelong
    AND a.ati_sitelat = b.ati_sitelat
;
SELECT * FROM astro_target_imaged_date;
UPDATE astro_target_imaged SET ati_targetname = 'UPDATED'||ati_targetname WHERE ati_targetname LIKE '%5';
SELECT a.ati_targetname, a.ati_telescope,b.atid_ccyymmdd,*  FROM astro_target_imaged AS a JOIN astro_target_imaged_date AS b 
    ON a.ati_targetname = b.ati_targetname
    AND a.ati_telescope = b.ati_telescope
    AND a.ati_focallength = b.ati_focallength
    AND a.ati_sitelong = b.ati_sitelong
    AND a.ati_sitelat = b.ati_sitelat
;
SELECT * FROM astro_target_imaged_date;
  • 请注意,前 3 列输出是演示的重要列,因此
    SELECT a.ati_targetname, a.ati_telescope,b.atid_ccyymmdd,* ....

结果是:-

原来的SELECT:-

  • 插入原始数据的所有排列

从父级删除 T1 后的

SELECT
:-

...._date 表(即级联删除的结果):-

    即所有 3 个 T1 排列已从被删除的单个 T1 父级中删除

单个T5父级更新后的SELECT:-

和 ...._日期表:-

    即已级联更新
© www.soinside.com 2019 - 2024. All rights reserved.