Триггер для динамического обновления рейтинга

69
6

Я хочу написать триггер для обновления вставки и удаления. O имеют одну таблицу с именем (tbl_rank), которые имеют первичный ключ (ID).

ID   Name   Rank
1 A 1
2 B 2
3 C 3
4 D 4
5 E 5

Теперь я хочу вставить новый ранг, но условия

1) if I enter 6 it will be 6
2) if I enter 7 it also should be 6 (I mean in sequence)
3) if I enter 2 than than entered rank will be 2 and 2 will be 3 and so on

Для триггера удаления

1) if I delete 5 the rank should be 1 to 4
2) if I delete 2 the rank would be rearranged and 3 should be 2 and 4 would be 3 and so on

для триггера обновления

1) if I update 3 to 5 than 4 would be 3 and 5 would be 4 
2) if I update 5 to 3 than 3 would be 4 and 4 would be 5

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

спросил(а) 2013-12-26T08:27:00+04:00 6 лет, 9 месяцев назад
1
Решение
108

Я хочу написать триггер для обновления вставки и удалить. У меня есть одна таблица с именем (tbl_rank), у которых есть первичный ключ (ID)

Пожалуйста, напишите DDL, чтобы люди не могли угадать, какие ключи, ограничения, декларативная ссылочная целостность, типы данных и т.д. В вашей схеме. Узнайте, как следовать правилам именования элементов данных ISO-11179 и правилам форматирования. Временные данные должны использовать форматы ISO-8601. Код должен быть в стандартном SQL как можно больше, а не локальном диалекте.

Это минимальное поведение на форумах SQL. Помещение "tbl_" на имя таблицы - это классический дефект дизайна, называемый "tbling", а имена столбцов также являются нарушениями правил ISO-11179. Теперь мы должны угадать ключи, типы данных и т.д. Вот моя догадка и уборка.

CREATE TABLE Prizes
(prize_id INTEGER NOT NULL PRIMARY KEY,
prize_name CHAR(1) NOT NULL,
prize_rank INTEGER NOT NULL);

INSERT INTO Prizes
VALUES
(1, 'A', 1),
(2, 'B', 2),
(3, 'C', 3),
(4, 'D', 4),
(5, 'E', 5);

Почему триггеры? RDBMS имеет виртуальные таблицы и столбцы. Это не колода перфокарт или магнитная лента. VIEW всегда актуальный и правильный.

CREATE VIEW Prize_List
AS
SELECT prize_id, prize_name,
ROW_NUMBER() OVER (ORDER BY prize_id)
AS prize_rank
FROM Prizes;

Но, возможно, лучше полностью удалить столбец prim_id и переупорядочить порядок отображения на основе столбца priority_rank:

CREATE TABLE Prizes
(prize_name CHAR(1) NOT NULL,
prize_rank INTEGER NOT NULL PRIMARY KEY);

Теперь используйте процедуры для манипулирования таблицей по мере необходимости.

CREATE PROCEDURE Swap_Prize_Ranks (@old_prize_rank INTEGER, @new_prize_rank INTEGER)
AS
UPDATE Prizes
SET prize_rank
= CASE prize_rank
WHEN @old_prize_rank
THEN @new_prize_rank
ELSE prize_rank + SIGN(@old_prize_rank - @new_prize_rank)
END
WHERE prize_rank BETWEEN @old_prize_rank AND @new_prize_rank
OR prize_rank BETWEEN @new_prize_rank AND @old_prize_rank;

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

CREATE PROCEDURE Close_Prize_Gaps()
AS
UPDATE Prizes
SET prize_rank
= (SELECT COUNT (P1.prize_rank)
FROM Prizes AS P1
WHERE P1.prize_rank <= Prizes.prize_rank);

ответил(а) 2014-01-04T03:45:00+04:00 6 лет, 9 месяцев назад
41

Существует предположение, что идентификатор не является столбцом автоидентификации.

CREATE TRIGGER trg_tbl_rank ON tbl_rank INSTEAD OF INSERT,DELETE,UPDATE AS BEGIN SET NOCOUNT ON;

 DECLARE @v_deleted_rank INT; DECLARE @v_inserted_rank INT; DECLARE @v_max_rank INT; SELECT @v_deleted_rank = COALESCE(rank, 0) FROM deleted; SELECT @v_inserted_rank = COALESCE(rank, 0) FROM inserted; SELECT @v_max_rank = COALESCE(MAX(rank), 0) FROM tbl_rank; IF @v_deleted_rank > 0 BEGIN DELETE FROM tbl_rank WHERE id = (SELECT id FROM deleted); UPDATE tbl_rank SET rank = rank - 1 WHERE rank > @v_deleted_rank; END IF @v_inserted_rank > 0 BEGIN IF @v_inserted_rank <= @v_max_rank BEGIN UPDATE tbl_rank SET rank = rank + 1 WHERE rank >= @v_inserted_rank; INSERT INTO tbl_rank (id, name, rank) SELECT id, name, @v_inserted_rank FROM inserted; END ELSE INSERT INTO tbl_rank (id, name, rank) SELECT id, name, @v_max_rank + 1 FROM inserted; END

END GO

Ниже приведены запросы к тестированию:

INSERT INTO tbl_rank (id, name, rank) VALUES (1, 'A', 1);

INSERT INTO tbl_rank (id, name, rank) VALUES (2, 'B', 2);

INSERT INTO tbl_rank (id, name, rank) VALUES (3, 'C', 3);

INSERT INTO tbl_rank (id, name, rank) VALUES (4, 'D', 4);

INSERT INTO tbl_rank (id, name, rank) VALUES (5, 'E', 5);

SELECT * FROM tbl_rank;

INSERT INTO tbl_rank (id, name, rank) VALUES (6, 'F', 7);

SELECT * FROM tbl_rank;

INSERT INTO tbl_rank (id, name, rank) VALUES (7, 'G', 2);

SELECT * FROM tbl_rank;

DELETE FROM tbl_rank WHERE rank = 7;

SELECT * FROM tbl_rank;

DELETE FROM tbl_rank WHERE rank = 2;

SELECT * FROM tbl_rank;

UPDATE tbl_rank SET rank = 5 WHERE rank = 3;

SELECT * FROM tbl_rank;

UPDATE tbl_rank SET rank = 3 WHERE rank = 5;

SELECT * FROM tbl_rank;

TRUNCATE TABLE tbl_rank;

ответил(а) 2014-01-04T02:58:00+04:00 6 лет, 9 месяцев назад
40

Можете ли вы не просто иметь tbl_rank как представление, то вам не нужны триггеры? Чтобы ранжировать их в представлении, вы можете использовать оконную функцию row_number() over (order by Id)

Как выполняется начальное обновление? Если вы знаете, что это обновление, вам нужно сделать удаление и вставить только для диапазона значений. Например, с 3 по 5. Вы удаляете записи с 3 по 5, а затем вставляете эти 3 записи снова с разными идентификаторами. Заявление об обновлении по существу делает это в любом случае

ответил(а) 2014-01-04T02:28:00+04:00 6 лет, 9 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема