Удалить все данные внешнего ключа при удалении первичного или наоборот

У меня есть структура таблицы, как это:

PrimaryTable -> p_id Здесь p_id является основным

SecondoryTable -> s_id p_id Здесь p_id — внешний ключ

ThirdTable -> t_id s_id Здесь s_id — внешний ключ

FourthTable -> f_id t_id Здесь t_id — внешний ключ

Итак, я удаляю один из моих p_id из PrimaryTable и хочу, чтобы его данные SecondoryTable также удалялись, И данные ThirdTable должны быть удалены со ссылкой на SecondoryTable, а данные FourthTable должны быть удалены со ссылкой на ThirdTable

Я знаю, что могу написать Delete запрос снизу вверх, но как это сделать для такого количества уровней??

Я нашел это, но не уверен в том, как: https://stackoverflow.com/a/9847308/1182021

Поскольку его четырехуровневая иерархия меня смущает.

EDIT1:

Что делать, если я хочу удалить Primary при удалении Child

Пожалуйста, предложите.


person Django Anonymous    schedule 26.07.2013    source источник
comment
Проверьте это   -  person Akhil    schedule 26.07.2013
comment
вам нужно добавить параметры удаления каскада во 2-ю, 3-ю и 4-ю таблицы при объявлении внешних ключей. После того, как вы внесете это изменение в свои таблицы, вы сможете удалить строки из всех 4 таблиц, используя только один запрос.   -  person Maximus2012    schedule 26.07.2013
comment
@Maximus2012 Хорошо, создавая отношения, я объявил это следующим образом: ON DELETE RESTRICT И ON UPDATE RESTRICT: Итак, вы предлагаете мне сделать ON DELETE CASCADE И ON UPDATE CASCADE? В моей структуре таблицы ??   -  person Django Anonymous    schedule 26.07.2013
comment
да. это правильно. Можете ли вы попробовать это и посмотреть, работает ли это?   -  person Maximus2012    schedule 26.07.2013
comment
publib .boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/   -  person Maximus2012    schedule 26.07.2013
comment
Хорошо, я пробую это сейчас, а пока не могли бы вы предложить, есть ли какие-то минусы в этом?   -  person Django Anonymous    schedule 26.07.2013
comment
Не вижу ничего плохого в таком подходе. Пока ваши отношения и ограничения верны (что, кажется, имеет место здесь), проблем быть не должно. То, что вы пытаетесь сделать, - это именно та причина, по которой существует внешний ключ в опции удаления каскада.   -  person Maximus2012    schedule 26.07.2013
comment
@Maximus2012 Maximus2012 То есть он каскадирует только дочерний или родительский??   -  person Django Anonymous    schedule 26.07.2013
comment
дочерний на основе изменений, которые вы вносите в родительский.   -  person Maximus2012    schedule 26.07.2013
comment
@Maximus2012 Что, если я хочу удалить родителей при удалении ребенка??   -  person Django Anonymous    schedule 26.07.2013
comment
это не так просто, насколько я знаю (но я могу ошибаться). Изучите это и посмотрите, поможет ли это: stackoverflow.com/questions/8169310/ для реализации чего-то подобного вам может потребоваться внести изменения в код вашего приложения и реализовать эту логику на уровне приложения, а не на уровне базы данных.   -  person Maximus2012    schedule 26.07.2013
comment
для удаления родителя при удалении дочернего элемента одним из способов сделать это было бы получить родительский идентификатор строки, которую вы собираетесь удалить, и, если удаление прошло успешно, затем удалить родительскую строку, идентификатор которой вы сохранили в переменной перед удалением дочерней строки.   -  person Maximus2012    schedule 26.07.2013
comment
дайте мне знать, если это не имеет смысла, и я добавлю ответ для этого случая, поскольку ваша первоначальная проблема, похоже, решена.   -  person Maximus2012    schedule 26.07.2013
comment
@Maximus2012 Maximus2012 Если возможно, вы можете дать ответ на этот вопрос. Поскольку оба ваших руководства соответствовали моему требованию. Спасибо и много. Давайте ответим, чтобы я мог отметить как принятый. Таким образом, другие люди могут напрямую перейти к вашему ответу. Спасибо!   -  person Django Anonymous    schedule 26.07.2013
comment
посмотри мой ответ. Посмотрите, поможет ли это. Ответ представляет собой своего рода псевдокод, и если вам нужно реализовать этот ответ, вам нужно написать код для выполнения запроса с использованием MySQLi/PDO.   -  person Maximus2012    schedule 26.07.2013


Ответы (3)


Согласно запросу OP, это ответ для случая, когда пользователь хочет удалить строку из родительской таблицы, когда строка удаляется из дочерней таблицы. Случай рекурсивного удаления всех дочерних элементов при удалении родителя работает с использованием опции MySQL ON DELETE CASCADE.

4 таблицы будут table1, table2, table3 и table4.

Если пользователь хочет удалить строку в таблице 2, а также соответствующую строку в таблице 1 (родитель таблицы 2), то в PHP:

// t2_delete_row_id is the id of the table 2 row to be deleted
// get the the parent of table2
$sql_get_parent = "select p_id from table2 where s_id = 't2_delete_row_id '";
// execute this query using MySQLi/PDO to get id of the parent row to be deleted
// assuming that id is t1_parent_row_id
// now delete the row from table 2:
// note that because of the foreign key constraints, 
// corresponding rows from table3 and table4 would also be deleted
$sql_delete_child = "delete from table2 where s_id = 't2_delete_row_id'";
if (mysqli_query($sql_delete_child)){
    // delete the parent row
    $sql_delete_parent = "delete from table1 where p_id = 't1_parent_row_id'";
}

эту логику можно расширить так, чтобы при удалении строки таблицы 3 соответствующие родительские (таблица 2) и «прародительские» (таблица 1) строки также удалялись. В этом случае может потребоваться небольшая рекурсия. И это, конечно, удалит дочерние строки в таблице 4 из-за ограничения внешнего ключа.

person Maximus2012    schedule 26.07.2013

Если вы не можете использовать FOREIGN KEYS (т.е. используя таблицы MyISAM), я бы создал для этого TRIGGER. Пример для первого ниже... вам нужно будет сделать по одному для каждой каскадной таблицы.

DELIMITER //
CREATE TRIGGER `pDeleteTrigger` BEFORE DELETE ON `PrimaryTable`
 FOR EACH ROW BEGIN
    DELETE FROM `SecondoryTable` WHERE NEW.`p_id` = `SecondoryTable`.`p_id`
END
//
DELIMITER ;
person cmorrissey    schedule 26.07.2013
comment
тогда должны быть триггеры для каждой таблицы? - person Maximus2012; 26.07.2013
comment
@ChristopherMorrissey Тогда концепция CASCADE бесполезна, согласно вашим знаниям, снимаю шляпу перед командой разработчиков mysql, они разработали бесполезную функцию. - person M Khalid Junaid; 26.07.2013
comment
@dianuj Я не могу понять, саркастичен ли ты, но CASCADE определенно полезен, если ты можешь использовать FOREIGN KEYS, это идеальное решение. Но иногда вы не можете использовать это, потому что вы используете MyISAM для полнотекстового поиска и т. д. - person cmorrissey; 26.07.2013
comment
Я согласен с Кристофером. Это решение будет работать для таблицы MyISAM. Кроме того, согласно второму запросу OP, функциональность триггера может быть расширена для удаления родительской строки при удалении дочерней строки. Мой ответ показывает, как это сделать в PHP, но это можно использовать для всего этого в базе данных. - person Maximus2012; 26.07.2013

У меня есть два подхода (если ваш язык Tsql)

1.- Процедура хранения

Идея состоит в том, чтобы иметь процедуру «spDelete_PrimaryTable», чтобы вы могли удалить регистры в четырех таблицах, написав что-то в tsql, например:

 exec spDelete_PrimaryTable
       @p_id= 25 /* (25 or watever p_id of primary table you want to delete)*/

(да, вы можете вызвать его из vb.net или любой другой страны, которую хотите.)

код будет примерно таким:

use [your_database]

CREATE PROCEDURE [dbo].[spDelete_PrimaryTable]
    @p_id nvarchar(MAX)
AS 
 begin  
    SET NOCOUNT ON;

delete from FourthTable where t_id in (
    select ThirdTable.t_id 
    from ThirdTable inner join SecondoryTable on ThirdTable.s_id = SecondoryTable.s_id
    where SecondoryTable.p_id = @p_id
)
go

delete from ThirdTable where s_id in (
    select SecondoryTable.s_id 
    where SecondoryTable.p_id = @p_id
)
go

    /*Lol, I forgot to eliminate from the "SecondoryTable" */
    delete from SecondoryTable.s_id 
    where SecondoryTable.p_id = @p_id

go

delete from PrimaryTable where p_id = @p_id
go

 END


GO

2.- Триггеры

похоже, что «Кристофер Моррисси» уже опубликовал это, пока я редактировал этот ответ XP

person Oaxas    schedule 26.07.2013