2013-11-27 2 views
2

Возможно ли в MySQL (в любой версии) объявить и использовать таблицу с самореферентным, а не нулевым столбцом внешнего ключа, ссылающимся на первичный ключ AUTO_INCREMENT той же таблицы?MySQL: Self-referential не null, auto_increment, внешний ключ?

По существу, я хотел бы создать следующую таблицу, строки которой представляют собой лес деревьев. Я хотел бы, чтобы корневые узлы в иерархии указывались parent_id строки, равной id (вместо того, чтобы разрешать NULL в parent_id указать корень).

например.

CREATE TABLE forest (
    id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, 
    parent_id BIGINT NOT NULL, 
     CONSTRAINT fk_forest_parent_id FOREIGN KEY(parent_id) REFERENCES forest(id), 
    name VARCHAR(20) NOT NULL UNIQUE 
); 

Создание этой таблицы работы (5.0.44sp1-предприятие-GPL-нт-журнал MySQL Enterprise Server (GPL)). Однако, как представляется, невозможно использовать LAST_INSERT_ID() для вставки parent_id корневых узлов (что не является чем-то большим сюрпризом). Ниже не работает, например:

INSERT INTO forest(parent_id, name) VALUES (LAST_INSERT_ID(), "root 1"); 

Следующая не работает, но больше не делает использование автоматического приращения:

INSERT INTO forest(id, parent_id, name) VALUES (1234, 1234, "root 1"); 

Есть ли способ использовать таблицу, определенную в этом в то время как все еще полагается на автоматически генерируемый PK, а также сохраняя все ограничения (NOT NULL и FOREIGN KEY)?

UPDATE - ВОЗМОЖНЫЕ РЕШЕНИЯ:

START TRANSACTION; 
SET FOREIGN_KEY_CHECKS = 0; 
INSERT INTO forest(parent_id, name) VALUES (0, "root X"); 
UPDATE forest SET parent_id = LAST_INSERT_ID() WHERE id = LAST_INSERT_ID(); 
SET FOREIGN_KEY_CHECKS = 1; /* This seems to be important. */ 
COMMIT; 
+0

Оставить родительский объект NULL. Если вы хотите, чтобы это было то же значение, что и id, вы можете добавить вычисляемый столбец «serious_this_parent_id As Coalesce (parent_id, id)» – gvee

+0

В таких ключах нет ничего плохого. Но использование 'LAST_INSERT_ID()' в том же самом заявлении, где идентификатор будет сгенерирован, очевидно, не будет работать. –

ответ

2

Это невозможно знать, что id из ряда будет до INSERT Завершает, поэтому вызов LAST_INSERT_ID() когда нет INSERT не было сделано ничего не делает. Вместо этого вам понадобятся два отдельных оператора (которые могут выполняться как транзакция в хранимой процедуре или что у вас есть).

INSERT INTO forest(name) VALUES ("root 1"); 
UPDATE forest SET parent_id = LAST_INSERT_ID() WHERE id = LAST_INSERT_ID(); 

Я не думаю, что имеет смысл для корневого узла ссылаться на себя как на родителя. Просто говорю.

+0

Пробовал (внутри СНВ-СТАВКИ ... КОМИТЕТ). Ошибка с «Ошибка: поле« parent_id »не имеет значения по умолчанию». – Paul

+0

@Paul Я об этом не думал. Вы можете либо присвоить значение «parent_id» с нулевым значением (которого вы, вероятно, хотите избежать), либо установить его на «0» –

+0

BTW. Мне показалось разумным использовать «PK == FK подразумевает root» как потому, что почти все узлы * do * имеют родительский (следовательно, NOT NULL) и, в частности, потому что корневые узлы на самом деле будут предварительно созданы и постоянно принадлежит родительскому типу (другая таблица). [Все это происходит под уровнем доступа к данным Java, над которым я работаю.] – Paul

Смежные вопросы