Django migration sql for conditional triggers

2019-03-03 20:21发布

问题:

I want to create a trigger that only inserts into table when the condition is met. I've tried using various combinations of IF/BEGIN/END and WHERE, but Django returns me an SQL syntax error each time.

Here, type_user_id refers to the person who triggers the like, and user_id refers to the person who receives the notification. It should only trigger when they are not the same person.

operations = [

    migrations.RunSQL(
        "DROP TRIGGER like_notification",
        """
        CREATE TRIGGER like_notification AFTER INSERT ON user_likes_article
        FOR EACH ROW
        IF (select user_id from channel WHERE channel_id IN
            (SELECT channel_id FROM article WHERE article_id = NEW.article_id)) <> NEW.user_id
        BEGIN
            INSERT INTO notification (type, type_id, article_id, is_read, type_user_id, user_id)
                VALUES ('like', NEW.article_id, NEW.article_id, false, NEW.user_id,
                    (SELECT user_id from channel WHERE channel_id IN
                        (SELECT channel_id FROM article WHERE article_id = NEW.article_id)
                    )
                )
        END;
        """
    )
]

>>>django.db.utils.ProgrammingError: (1064, "You have an error in your SQL syntax; 
check the manual that corresponds to your MariaDB server version for the right syntax 
to use near 'BEGIN\n INSERT INTO notification (type, type_id, article_id, is_re' at line 5")

and

CREATE TRIGGER like_notification AFTER INSERT ON user_likes_article
        FOR EACH ROW
        BEGIN
            DECLARE @user_same Boolean;
            SELECT 1 into @user_same
            FROM channel
            WHERE channel_id IN (select channel_id FROM article where article_id = NEW.article_id)
            AND user_id = NEW.user_id;

            IF @user_same <> 1
            THEN
                INSERT INTO notification (type, type_id, article_id, is_read, type_user_id, user_id,)
                VALUES ('like', NEW.article_id, NEW.article_id, false, NEW.user_id, (
                    SELECT user_id from channel WHERE channel_id IN (
                         SELECT channel_id FROM article WHERE article_id = NEW.article_id)
                    )
            END IF;
        END;

>>>You have an error in your SQL syntax; check the manual that corresponds to your 
MariaDB server version for the right syntax to use near '@user_same Boolean;\n                SELECT 1 into @user_same\n                FRO' at line 4"

and

CREATE TRIGGER like_notification AFTER INSERT ON user_likes_article
        FOR EACH ROW
        INSERT INTO notification (type, type_id, article_id, is_read, type_user_iduser_id)
        VALUES ('like', NEW.article_id, NEW.article_id, false, NEW.user_id,
            (
            SELECT user_id from channel WHERE channel_id IN
                (SELECT channel_id FROM article WHERE article_id = NEW.article_id)
            )
        WHERE NOT user_id = NEW.user_id;

>>>You have an error in your SQL syntax; check the manual that corresponds to your 
MariaDB server version for the right syntax to use near 'WHERE NOT user

I don't really understand why none of them work. Any help would be much appreciated!

回答1:

@variables are not DECLARED.

Either:

DECLARE user_same BOOLEAN;
SELECT 1 INTO user_same WHERE ...

or

SELECT @user_same := 1 WHERE ...

Better yet, this avoids the need for the variable.

IF (EXISTS SELECT * FROM ...)

Also, don't use the construct IN ( SELECT ... ); it is usually better to use WHERE EXISTS ( SELECT * FROM ... ) or JOIN ... ON ....

(There may be more problems after fixing those.)



回答2:

Another easy way to do this.

You should add any symbols between ; delimiters for the appropriate converting MySQL syntax to the raw SQL.

CREATE TRIGGER trigger_name BEFORE INSERT ON table
FOR EACH ROW
BEGIN
IF NEW.number <> 'anynumber' AND NEW.number <> 'anynumber'
  THEN
    SET NEW.number = 'anynumber'; --
END IF; --
END

This example works due to the dash symbols.