Загрузка данных


-- ============================================
-- 1. ФУНКЦИЯ И ПРОЦЕДУРА ПОПУЛЯРНОСТИ КНИГИ
-- ============================================

DELIMITER $$

DROP FUNCTION IF EXISTS GetBookPopularity $$
CREATE FUNCTION GetBookPopularity(p_book_id INT)
RETURNS INT
DETERMINISTIC
BEGIN
    DECLARE total INT;

    SELECT COUNT(*)
    INTO total
    FROM issues
    WHERE book_id = p_book_id;

    RETURN total;
END $$

DROP PROCEDURE IF EXISTS ShowBookPopularity $$
CREATE PROCEDURE ShowBookPopularity(
    IN p_book_id INT
)
BEGIN
    DECLARE cnt INT;

    SELECT COUNT(*)
    INTO cnt
    FROM books
    WHERE id = p_book_id;

    IF cnt > 0 THEN

        DROP TEMPORARY TABLE IF EXISTS temp_popularity;

        CREATE TEMPORARY TABLE temp_popularity(
            book_id INT,
            popularity INT
        );

        INSERT INTO temp_popularity
        VALUES(
            p_book_id,
            GetBookPopularity(p_book_id)
        );

        SELECT * FROM temp_popularity;

    ELSE

        SELECT 'Книга не существует' AS Ошибка;

    END IF;
END $$

DELIMITER ;

-- ПРОВЕРКА

CALL ShowBookPopularity(1);
CALL ShowBookPopularity(100);

-- ============================================
-- 2. КАТЕГОРИЯ ВОЗРАСТА ЧИТАТЕЛЯ
-- ============================================

DELIMITER $$

DROP FUNCTION IF EXISTS GetAgeCategory $$
CREATE FUNCTION GetAgeCategory(p_age INT)
RETURNS VARCHAR(20)
DETERMINISTIC
BEGIN

    DECLARE result_age VARCHAR(20);

    IF p_age < 25 THEN
        SET result_age = 'Молодой';

    ELSEIF p_age BETWEEN 25 AND 60 THEN
        SET result_age = 'Взрослый';

    ELSE
        SET result_age = 'Пенсионер';

    END IF;

    RETURN result_age;

END $$

DROP PROCEDURE IF EXISTS UpdateAgeCategories $$
CREATE PROCEDURE UpdateAgeCategories()
BEGIN

    ALTER TABLE readers
    ADD COLUMN age_category VARCHAR(20);

    UPDATE readers
    SET age_category = GetAgeCategory(age);

    SELECT * FROM readers;

END $$

DELIMITER ;

-- ПРОВЕРКА

CALL UpdateAgeCategories();

-- ============================================
-- 3. РАСЧЁТ ШТРАФОВ
-- ============================================

DELIMITER $$

DROP FUNCTION IF EXISTS CalculateFine $$
CREATE FUNCTION CalculateFine(
    p_issue_date DATE,
    p_return_date DATE
)
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN

    DECLARE total_days INT;
    DECLARE fine_result DECIMAL(10,2);

    IF p_return_date IS NULL THEN
        SET total_days = DATEDIFF(CURDATE(), p_issue_date);
    ELSE
        SET total_days = DATEDIFF(p_return_date, p_issue_date);
    END IF;

    IF total_days <= 7 THEN
        SET fine_result = 0;
    ELSE
        SET fine_result = total_days - 7;
    END IF;

    RETURN fine_result;

END $$

DROP PROCEDURE IF EXISTS UpdateFines $$
CREATE PROCEDURE UpdateFines()
BEGIN

    UPDATE issues
    SET fine = CalculateFine(issue_date, return_date)
    WHERE return_date IS NULL
    OR DATEDIFF(return_date, issue_date) > 7;

    SELECT * FROM issues;

END $$

DELIMITER ;

-- ПРОВЕРКА

CALL UpdateFines();

-- ============================================
-- 4. СРЕДНИЙ РЕЙТИНГ АВТОРОВ
-- ============================================

DELIMITER $$

DROP FUNCTION IF EXISTS GetAuthorAverageRating $$
CREATE FUNCTION GetAuthorAverageRating(
    p_author_id INT
)
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN

    DECLARE avg_rating DECIMAL(10,2);

    SELECT IFNULL(AVG(i.rating), 0)
    INTO avg_rating
    FROM issues i
    JOIN books b ON i.book_id = b.id
    JOIN book_authors ba ON b.id = ba.book_id
    WHERE ba.author_id = p_author_id
    AND i.rating IS NOT NULL;

    RETURN avg_rating;

END $$

DROP PROCEDURE IF EXISTS BuildAuthorRatings $$
CREATE PROCEDURE BuildAuthorRatings()
BEGIN

    DROP TABLE IF EXISTS author_ratings;

    CREATE TABLE author_ratings(
        author_id INT,
        author_name VARCHAR(100),
        avg_rating DECIMAL(10,2)
    );

    INSERT INTO author_ratings
    SELECT
        a.id,
        a.name,
        GetAuthorAverageRating(a.id)
    FROM authors a;

    SELECT * FROM author_ratings;

END $$

DELIMITER ;

-- ПРОВЕРКА

CALL BuildAuthorRatings();

-- ============================================
-- 5. РЕКОМЕНДАЦИИ КНИГ ЧИТАТЕЛЮ
-- ============================================

DELIMITER $$

DROP FUNCTION IF EXISTS CountGenreReads $$
CREATE FUNCTION CountGenreReads(
    p_reader_id INT,
    p_genre VARCHAR(50)
)
RETURNS INT
DETERMINISTIC
BEGIN

    DECLARE total INT;

    SELECT COUNT(*)
    INTO total
    FROM issues i
    JOIN books b ON i.book_id = b.id
    WHERE i.reader_id = p_reader_id
    AND b.genre = p_genre;

    RETURN total;

END $$

DROP PROCEDURE IF EXISTS RecommendBooks $$
CREATE PROCEDURE RecommendBooks(
    IN p_reader_id INT
)
BEGIN

    DECLARE cnt INT;

    SELECT COUNT(*)
    INTO cnt
    FROM readers
    WHERE id = p_reader_id;

    IF cnt > 0 THEN

        SELECT
            b.id,
            b.title,
            b.genre,
            CountGenreReads(p_reader_id, b.genre) AS genre_score
        FROM books b
        ORDER BY genre_score DESC
        LIMIT 3;

    ELSE

        SELECT 'Читатель не найден' AS Ошибка;

    END IF;

END $$

DELIMITER ;

-- ПРОВЕРКА

CALL RecommendBooks(1);
CALL RecommendBooks(100);

-- ============================================
-- 6. СТОИМОСТЬ КНИГ ПОСЛЕ ГОДА
-- ============================================

DELIMITER $$

DROP FUNCTION IF EXISTS SumBookPricesAfterYear $$
CREATE FUNCTION SumBookPricesAfterYear(
    p_year INT
)
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN

    DECLARE total_price DECIMAL(10,2);

    SELECT IFNULL(SUM(price), 0)
    INTO total_price
    FROM books
    WHERE pub_year > p_year;

    RETURN total_price;

END $$

DROP PROCEDURE IF EXISTS CreateLibraryStats $$
CREATE PROCEDURE CreateLibraryStats(
    IN p_year INT
)
BEGIN

    DECLARE cnt INT;

    SELECT COUNT(*)
    INTO cnt
    FROM books
    WHERE pub_year > p_year;

    IF cnt > 0 THEN

        CREATE TABLE IF NOT EXISTS library_stats(
            stat_year INT,
            total_price DECIMAL(10,2)
        );

        INSERT INTO library_stats
        VALUES(
            p_year,
            SumBookPricesAfterYear(p_year)
        );

        SELECT * FROM library_stats;

    ELSE

        SELECT 'Подходящих книг нет' AS Результат;

    END IF;

END $$

DELIMITER ;

-- ПРОВЕРКА

CALL CreateLibraryStats(1900);
CALL CreateLibraryStats(3000);