SQL: сложное удаление - PullRequest
1 голос
/ 07 ноября 2008

Я в основном создал несколько столов, с которыми можно поиграться: у меня есть два основных стола и стол соединения многих-многих. Вот DDL: (я использую HSQLDB)

CREATE TABLE PERSON
(
    PERSON_ID INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, 
    NAME VARCHAR(50), MAIN_PERSON_ID INTEGER
)

CREATE TABLE JOB
(
    JOB_ID INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, 
    NAME VARCHAR(50)
)
CREATE TABLE JOB_PERSON
(
    PERSON_ID INTEGER, 
    JOB_ID INTEGER
)
ALTER TABLE JOB_PERSON ADD 
    CONSTRAINT FK_PERSON_JOB FOREIGN KEY(PERSON_ID) 
    REFERENCES PERSON ON DELETE CASCADE ON UPDATE CASCADE 

ALTER TABLE JOB_PERSON ADD
    CONSTRAINT FK_JOB_PERSON FOREIGN KEY(JOB_ID) 
    REFERENCES JOB ON DELETE CASCADE ON UPDATE CASCADE

ALTER TABLE PERSON ADD
    CONSTRAINT FK_PERSON_PERSON FOREIGN KEY(MAIN_PERSON_ID) 
    REFERENCES PERSON ON DELETE CASCADE ON UPDATE CASCADE

insert into person values(null,'Arthur', null);
insert into person values(null,'James',0);
insert into job values(null, 'Programmer')
insert into job values(null, 'Manager')
insert into job_person values(0,0);
insert into job_person values(0,1);
insert into job_person values(1,1);

Я хочу создать оператор удаления, который удаляет сирот из JOB (если существует только одна запись в таблице объединения для конкретного задания) на основе PERSON.PERSON_ID.

На псевдоязыке:

delete from job where job_person.job_id=job.job_id 
AND count(job_person.job_id)=1 AND job_person.person_id=X

Где X - это некий person_id. Я пробовал много разных способов; Я думаю, что это часть "COUNT", которая вызывает проблемы. Я новичок в SQL, поэтому любая помощь будет принята с благодарностью.

Ответы [ 2 ]

2 голосов
/ 07 ноября 2008

Я не следую.

Вы не можете удалить JOB строки, которые имеют JOB_PERSON строки (даже одну) из-за ваших ограничений FK. Таким образом, невозможно удалить JOB строк на основе PERSON строк.

JOB_PERSON строки должны быть удалены перед тем, как JOB или PERSON могут быть удалены.

Если вы хотите удалить все JOB строки без JOB_PERSON, то один из способов:

DELETE FROM JOB
WHERE JOB_ID NOT IN (
    SELECT JOB_ID
    FROM JOB_PERSON
)

Если вы хотите удалить все JOB_PERSON строки для конкретного человека, а затем всех сирот, сделайте это в два шага:

DELETE FROM JOB_PERSON
WHERE PERSON_ID = X

DELETE FROM JOB
WHERE JOB_ID NOT IN (
    SELECT JOB_ID
    FROM JOB_PERSON
)

Если вы хотите удалить только сироты JOB, ранее связанные с X, вам нужно будет сохранить их во временной таблице перед первым удалением.

INSERT INTO TEMP_TABLE
SELECT JOB.JOB_ID
FROM JOB
INNER JOIN JOB_PERSON
    ON JOB_PERSON.JOB_ID = JOB.JOB_ID
WHERE JOB_PERSON.PERSON_ID = X

DELETE FROM PERSON
WHERE PERSON_ID = X

-- YOUR CASCADING DELETE DOES THIS:
/*
DELETE FROM JOB_PERSON
WHERE PERSON_ID = X
*/

-- Now clean up (only) new orphans on the other side
DELETE FROM JOB
WHERE JOB_ID NOT IN (
    SELECT JOB_ID
    FROM JOB_PERSON
)
AND JOB_ID IN (
    SELECT JOB_ID
    FROM TEMP_TABLE
)
1 голос
/ 07 ноября 2008

Это удалит из вашей таблицы записи JOB, которые не имеют записи в таблице JOB_PERSON (Orpheans).

DELETE FROM JOB
WHERE JOB_ID NOT IN (
    SELECT JOB_ID
    FROM JOB_PERSON
)

Вы не можете удалить строки, которые связаны посторонним в другой таблице ...

...