Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

курсач / 03_Procedures

.sql
Скачиваний:
0
Добавлен:
27.12.2025
Размер:
8 Кб
Скачать
/* =================================================================================
   СКРИПТ 03: ХРАНИМЫЕ ПРОЦЕДУРЫ (BUSINESS LOGIC)
   ================================================================================= */

USE CircuitDB;
GO

PRINT '=============================================================';
PRINT 'Создание хранимых процедур (Business Logic)...';
PRINT 'Время запуска: ' + CONVERT(VARCHAR(30), GETDATE(), 120);
PRINT '=============================================================';
GO

/* =============================================
   1. ПРОЦЕДУРА ПОИСКА (Search)
   ============================================= */
IF OBJECT_ID('[Stock].[usp_SearchComponents]', 'P') IS NOT NULL DROP PROC [Stock].[usp_SearchComponents];
GO

CREATE PROCEDURE [Stock].[usp_SearchComponents]
    @Keyword NVARCHAR(100) = NULL,
    @ManufacturerID INT = NULL,
    @CategoryID INT = NULL
AS
BEGIN
    SET NOCOUNT ON;

    SELECT 
        c.ComponentID,
        c.PartNumber,
        m.Name AS Manufacturer,
        cat.Name AS Category,
        p.Name AS Package,
        c.Description,
        -- Генерируем дату "на лету" в момент вызова, в БД она не хранится
        GETDATE() AS [ReportTime],
        CASE WHEN c.IsActive = 1 THEN 'Yes' ELSE 'No' END AS [InProduction]
    FROM [Stock].[Components] c
    JOIN [Ref].[Manufacturers] m ON c.ManufacturerID = m.ManufacturerID
    JOIN [Ref].[Categories] cat ON c.CategoryID = cat.CategoryID
    JOIN [Ref].[PackageTypes] p ON c.PackageID = p.PackageID
    WHERE 
        (@Keyword IS NULL OR c.PartNumber LIKE '%' + @Keyword + '%')
        AND
        (@ManufacturerID IS NULL OR c.ManufacturerID = @ManufacturerID)
        AND
        (@CategoryID IS NULL OR c.CategoryID = @CategoryID)
    ORDER BY c.PartNumber;
END
GO
PRINT 'Proc [usp_SearchComponents] created.';
GO

/* =============================================
   2. ПРОЦЕДУРА ДОБАВЛЕНИЯ (Create)
   Исправлено: RAISERROR вместо THROW
   ============================================= */
IF OBJECT_ID('[Stock].[usp_CreateComponent]', 'P') IS NOT NULL DROP PROC [Stock].[usp_CreateComponent];
GO

CREATE PROCEDURE [Stock].[usp_CreateComponent]
    @PartNumber NVARCHAR(100),
    @ManufacturerID INT,
    @CategoryID INT,
    @PackageID INT,
    @Description NVARCHAR(1000) = NULL,
    @NewID INT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;

    -- Проверка до транзакции (так безопаснее для лога)
    IF EXISTS (SELECT 1 FROM [Stock].[Components] WHERE PartNumber = @PartNumber)
    BEGIN
        RAISERROR('Ошибка: Компонент с таким артикулом уже существует.', 16, 1);
        RETURN;
    END

    BEGIN TRY
        BEGIN TRANSACTION;

        INSERT INTO [Stock].[Components] (PartNumber, ManufacturerID, CategoryID, PackageID, Description, IsActive)
        VALUES (@PartNumber, @ManufacturerID, @CategoryID, @PackageID, @Description, 1);

        SET @NewID = SCOPE_IDENTITY();

        COMMIT TRANSACTION;
        
        PRINT 'Компонент создан. ID: ' + CAST(@NewID AS VARCHAR(10)) + '. Время: ' + CONVERT(VARCHAR(30), GETDATE(), 120);
    END TRY
    BEGIN CATCH
        -- Если случилась ошибка (например, сбой сети или диска)
        IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
        
        DECLARE @ErrMsg NVARCHAR(4000) = ERROR_MESSAGE();
        RAISERROR(@ErrMsg, 16, 1);
    END CATCH
END
GO
PRINT 'Proc [usp_CreateComponent] created.';
GO

/* =============================================
   3. ПРОЦЕДУРА ОБНОВЛЕНИЯ (Update)
   ============================================= */
IF OBJECT_ID('[Stock].[usp_UpdateComponentStatus]', 'P') IS NOT NULL DROP PROC [Stock].[usp_UpdateComponentStatus];
GO

CREATE PROCEDURE [Stock].[usp_UpdateComponentStatus]
    @ComponentID INT,
    @IsActive BIT,
    @NewDescription NVARCHAR(1000) = NULL
AS
BEGIN
    SET NOCOUNT ON;

    IF NOT EXISTS (SELECT 1 FROM [Stock].[Components] WHERE ComponentID = @ComponentID)
    BEGIN
        RAISERROR('Ошибка: Компонент с ID %d не найден.', 16, 1, @ComponentID);
        RETURN;
    END

    UPDATE [Stock].[Components]
    SET 
        IsActive = @IsActive,
        Description = ISNULL(@NewDescription, Description)
    WHERE ComponentID = @ComponentID;

    PRINT 'Статус обновлен ' + CONVERT(VARCHAR(30), GETDATE(), 120);
END
GO
PRINT 'Proc [usp_UpdateComponentStatus] created.';
GO

/* =============================================
   4. ПРОЦЕДУРА ЭКСПОРТА (XML Export)
   Внимание: Мы используем английские имена колонок, 
   которые будут в View v_FullComponentReport (скрипт 04).
   Дату создания убрали.
   ============================================= */
IF OBJECT_ID('[Stock].[usp_ExportReportToXML]', 'P') IS NOT NULL DROP PROC [Stock].[usp_ExportReportToXML];
GO

CREATE PROCEDURE [Stock].[usp_ExportReportToXML]
AS
BEGIN
    SET NOCOUNT ON;
    
    -- Вывод текущей даты генерации отчета как атрибута корневого элемента? 
    -- Нет, просто генерируем данные.
    
    -- ВАЖНО: SSMS может подчеркивать v_FullComponentReport красным, 
    -- так как View еще не создана. Это нормально, скрипт выполнится.
    SELECT 
        PartNumber      AS [@Article],
        Manufacturer    AS [@Manufacturer],
        Category        AS [@Category],
        Package         AS [@Package],
        Description     AS [@Description]
    FROM [Stock].[v_FullComponentReport]
    FOR XML PATH('Component'), ROOT('CircuitReport');
END
GO
PRINT 'Proc [usp_ExportReportToXML] created.';
GO

/* =============================================
   5. ПРОЦЕДУРА ИМПОРТА (XML Import)
   Исправлено: RAISERROR и обработка ошибок
   ============================================= */
IF OBJECT_ID('[Stock].[usp_ImportComponentsFromXML]', 'P') IS NOT NULL DROP PROC [Stock].[usp_ImportComponentsFromXML];
GO

CREATE PROCEDURE [Stock].[usp_ImportComponentsFromXML]
    @XmlData XML
AS
BEGIN
    SET NOCOUNT ON;
    
    IF @XmlData IS NULL
    BEGIN
        RAISERROR('Ошибка: Передан пустой XML.', 16, 1);
        RETURN;
    END

    BEGIN TRY
        BEGIN TRANSACTION;

        INSERT INTO [Stock].[Components] (PartNumber, ManufacturerID, CategoryID, PackageID, Description, IsActive)
        SELECT
            Node.value('@Article', 'NVARCHAR(100)'),
            -- Ищем ID по имени. Если не нашли - ставим 1 (по умолчанию)
            ISNULL((SELECT Top 1 ManufacturerID FROM [Ref].[Manufacturers] WHERE Name = Node.value('@Manufacturer', 'NVARCHAR(100)')), 1),
            ISNULL((SELECT Top 1 CategoryID FROM [Ref].[Categories] WHERE Name = Node.value('@Category', 'NVARCHAR(100)')), 1),
            ISNULL((SELECT Top 1 PackageID FROM [Ref].[PackageTypes] WHERE Name = Node.value('@Package', 'NVARCHAR(100)')), 1),
            Node.value('@Description', 'NVARCHAR(1000)'),
            1
        FROM @XmlData.nodes('/CircuitReport/Component') AS T(Node)
        WHERE NOT EXISTS (
            -- Защита от дубликатов по Артикулу
            SELECT 1 FROM [Stock].[Components] c 
            WHERE c.PartNumber = Node.value('@Article', 'NVARCHAR(100)')
        );

        DECLARE @Count INT = @@ROWCOUNT;
        COMMIT TRANSACTION;
        
        PRINT 'Импортировано компонентов: ' + CAST(@Count AS VARCHAR(10));
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
        
        DECLARE @Err NVARCHAR(4000) = ERROR_MESSAGE();
        RAISERROR(@Err, 16, 1);
    END CATCH
END
GO
PRINT 'Proc [usp_ImportComponentsFromXML] created.';
GO

PRINT '=============================================================';
PRINT 'Скрипт 03 выполнен успешно.';
PRINT 'Время завершения: ' + CONVERT(VARCHAR(30), GETDATE(), 120);
PRINT '=============================================================';
GO
Соседние файлы в папке курсач