Может ли MySQL ограничиться на основе значения NULL в сочетании с идентификатором? - PullRequest
0 голосов
/ 27 марта 2012

Я использую django-mptt для создания древовидной структуры модели в веб-приложении.

К сожалению, время от времени я получаю дубликаты корневых узлов в дереве.

Этибудет иметь значение NULL в качестве parent_id и тот же tree_id, например:

+--------+-----------+---------+
| id     | parent_id | tree_id |
+--------+-----------+---------+
| 159092 |      NULL |   52098 | 
| 159093 |      NULL |   52098 | 
+--------+-----------+---------+

Есть ли способ остановить это на уровне базы данных?
Могу ли я установить ограничение в MySQL, чтобы избежать получения двух илибольше элементов с NULL в качестве parent_id и тем же tree_id?

Модель из models.py с удаленными нерелевантными полями:

class Message(MPTTModel):
    # Threaded messages
    text = textmodels.TextField()

1 Ответ

0 голосов
/ 28 марта 2012

Простой ответ - нет, но вы можете создать триггеры вставки и обновления, которые заблокируют новое значение.Если вы используете MySQL> = 5.5, вы можете использовать что-то вроде этого -

DELIMITER |

DROP TRIGGER IF EXISTS before_msg_insert|

CREATE TRIGGER before_msg_insert BEFORE INSERT ON message
FOR EACH ROW
BEGIN
    DECLARE xid INT DEFAULT 0;
    IF (NEW.parent_id IS NULL) THEN

        SET xid = (SELECT id FROM message WHERE tree_id = NEW.tree_id AND parent_id IS NULL);

        IF (xid > 0) THEN
            SET @msg = CONCAT("Root node already exists. ID: ", xid);
            SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = @msg;
        END IF;

    END IF;
END|

DROP TRIGGER IF EXISTS before_msg_update|

CREATE TRIGGER before_msg_update BEFORE UPDATE ON message
FOR EACH ROW
BEGIN
    DECLARE xid INT DEFAULT 0;
    IF (NEW.parent_id IS NULL) THEN

        SET xid = (SELECT id FROM message WHERE tree_id = NEW.tree_id AND id <> NEW.id AND parent_id IS NULL);

        IF (xid > 0) THEN
            SET @msg = CONCAT("Root node already exists. ID: ", xid);
            SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = @msg;
        END IF;

    END IF;
END|

DELIMITER ;
...