
Курсовая работа. БД
.pdf
21
Рисунок 16 - Результат назначения прав
Так как директору допустим лишь просмотр всех таблиц, для назначение ему таких полномочий можно использовать:
GRANT SELECT ON ALL TABLES IN SCHEMA public TO director;
Рисунок 17 - Результат назначения прав
Назначение прав для модератора представлено ниже:
GRANT SELECT ON friends TO moderator;
GRANT SELECT ON communities TO moderator;
GRANT SELECT, INSERT, UPDATE, DELETE ON users TO moderator;

22
Рисунок 18 - Результат назначения прав
Назначение прав для поддержки пользователей представлено ниже:
GRANT SELECT ON users TO tech_support;
Рисунок 19 - Результат назначения прав
23
Проектирование пользовательского интерфейса
Первое, на что следует обратить внимание - это группы друзей пользователя. В них можно занести лишь тех пользователей, с которыми у пользователя взаимная дружба. Для добавления пользователя в группу, можно завести функцию вида:
CREATE OR REPLACE FUNCTION adding_friend_to_group(gr_id integer, fr_id
integer, us_id integer) RETURNS BOOLEAN AS
$$
begin
if (not exists (select owner_id from groups g where g.owner_id
= us_id and g.id = gr_id)) THEN
raise exception 'Группа с идентификатором --> % не принадлежит пользователю --> %', gr_id, us_id;
end if;
if ((select count(user_id) from friends where user_id = us_id and friend_id = fr_id or user_id = fr_id and friend_id = us_id) != 2) then raise exception 'У пользователей --> % и % дружба не
взаимна', us_id, fr_id;
end if;
insert into friend_group (group_id, friend_id) values (gr_id,
fr_id);
return true;
end;
$$ LANGUAGE plpgsql;

24
Рисунок 20 - Результат создания функции
Рисунок 21 - Результат добавления пользователя в группу друзей
Рисунок 22 - Попытка добавить друга в группу, которая не принадлежит пользователю

25
Рисунок 23 - Попытка добавить пользователя в группу, дружба с которым не взаимна
Стандартные средства реляционной БД не позволяют поддерживать целостность в части групп. То есть, например, возможно ситуация, когда пользователь добавит друга в группу. Но, в какой-то момент, дружба может стать невзаимной в случае, если одна из сторон удалит запись из таблицы friends. В таком случае пользователя также не должно быть в группе друзей. Для этого потребуется реализовать триггер.
Функция, которая будет использоваться в триггере:
CREATE OR REPLACE FUNCTION delete_from_friend_group() RETURNS TRIGGER AS
$$
begin
delete from friend_group where friend_id = old.friend_id and group_id IN (select id from groups where owner_id = old.user_id);
delete from friend_group where friend_id = old.user_id and group_id IN (select id from groups where owner_id = old.friend_id);
RETURN old;
END;
$$ LANGUAGE plpgsql;
Триггер:
CREATE TRIGGER trigger_delete_from_friend_group before delete ON friends
for each row
EXECUTE FUNCTION delete_from_friend_group();

26
Попробуем использовать созданный триггер.
Рисунок 24 - Содержимое таблицы friend_group
Рисунок 25 - Содержимое таблицы friends

27
Попробуем удалить пользователя 3 из друзей пользователя 1, в одностороннем порядке.
Рисунок 26 - Запрос на удаление
Рисунок 27 - Содержимое таблицы friends после удаления

28
Рисунок 28 - Содержимое таблицы friend_group после удаления
Также для сложных запросов можно ввести отдельные функции, чтобы при необходимости - не требовалось вспоминать его синтаксис. Например, запрос на получение распределения друзей по группам определенного пользователя. Скрипт будет иметь вид:
CREATE |
OR |
REPLACE |
FUNCTION |
get_count_friend_for_groups(us_id |
integer) RETURNS table (title varchar, count_users bigint) AS $$ |
||||
begin |
|
|
|
|
return query select g.title as title, count(fg.group_id) as |
||||
count_users from groups g |
|
|
||
|
|
|
left join |
friend_group fg on fg.group_id = |
g.id |
|
|
|
|
|
|
|
where g.owner_id = us_id |
|
|
|
|
group by g.title, fg.group_id; |
|
END; |
|
|
|
|
$$ LANGUAGE plpgsql; |
|
|
|
Рисунок 29 - Результат вызова созданной функции

29
Для того, чтобы быстрее и удобнее создавать новые группы друзей, введена функция:
CREATE OR REPLACE FUNCTION create_groups_for_user (titles varchar[], user_id integer) RETURNS boolean AS $$
declare
gr_title varchar;
begin
foreach gr_title in array $1 loop
insert into groups (owner_id, title) values (user_id,
gr_title);
end loop; return true;
END;
$$ LANGUAGE plpgsql;
Рисунок 30 - Результат вызова функции
Рисунок 31 - Результат вызова функции

30
Предположим, что при блокировке пользователя - мы должны удалить все связанные с ним записи из таблицы друзей. Для этой цели потребуется ввести триггер. Но, перед его написанием, нужно немного подправить модель данных таблицы users, введя поле active:
alter table users add column active boolean default true; alter table users alter column active set not null;
Рисунок 32 - Результат добавления колонки
Листинг функции, используемой в триггере:
CREATE OR REPLACE FUNCTION delete_friends_on_deactivation_user() RETURNS
TRIGGER AS $$ begin
delete from friends where user_id = old.id or friend_id =
old.id;
RETURN old;
END;
$$ LANGUAGE plpgsql;
Триггер, который будет вызывать перед обновлением записи в таблице users и изменении у нее значения active на false:
CREATE TRIGGER trigger_on_deactivation_user before update ON users
for each row
when (old.active != new.active and new.active = false)
EXECUTE FUNCTION delete_friends_on_deactivation_user();