курсач / Наволоцкий_1302_v2
.pdf03_Procedures.sql
/*
============================================================
=====================
СКРИПТ 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
81
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
82
(@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
83
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
84
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;
85
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];
86
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
/* =============================================
87
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 (по умолчанию)
88
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;
89
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
90
