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

курсач / Наволоцкий_1302_v2

.pdf
Скачиваний:
0
Добавлен:
27.12.2025
Размер:
2.69 Mб
Скачать

04_ViewsAndFunctions.sql

/*

============================================================

=====================

СКРИПТ 04: ПРЕДСТАВЛЕНИЯ И ФУНКЦИИ (VIEWS & UDF)

Схемы: [Stock]

============================================================

===================== */

USE CircuitDB;

GO

PRINT '=========================================================== ==';

PRINT 'Создание функций и представлений...';

PRINT 'Время запуска: ' + CONVERT(VARCHAR(30), GETDATE(), 120);

PRINT '=========================================================== ==';

GO

/* =============================================

1. SCALAR FUNCTION (Скалярная функция)

Тип: Простая Задача: Склеить значение и единицу измерения.

============================================= */

91

IF OBJECT_ID('[Stock].[udf_FormatValue]', 'FN') IS NOT NULL

DROP FUNCTION [Stock].[udf_FormatValue];

GO

CREATE FUNCTION [Stock].[udf_FormatValue]

(

@Value NVARCHAR(100),

@Unit NVARCHAR(20)

)

RETURNS NVARCHAR(150)

AS

BEGIN

DECLARE @Result NVARCHAR(150);

-- Логика: Если единицы измерения нет, возвращаем просто число

IF @Unit IS NULL OR @Unit = ''

SET @Result = @Value;

ELSE

SET @Result = @Value + ' ' + @Unit;

RETURN @Result;

END

GO

PRINT 'Function [udf_FormatValue] created.';

GO

/* =============================================

2. INLINE TABLE-VALUED FUNCTION (Простая табличная)

92

Тип: Inline TVF (содержит только RETURN SELECT)

Задача: Получить параметры компонента в отформатированном виде.

============================================= */

IF OBJECT_ID('[Stock].[udf_GetComponentParams]', 'IF') IS

NOT NULL DROP FUNCTION [Stock].[udf_GetComponentParams];

GO

CREATE FUNCTION [Stock].[udf_GetComponentParams]

(

@CompID INT

)

RETURNS TABLE

AS

RETURN

(

SELECT

ParamName AS [Parameter],

-- Вызов скалярной функции внутри табличной

[Stock].[udf_FormatValue](ParamValue, Unit) AS [ValueFormatted]

FROM [Stock].[ComponentParams]

WHERE ComponentID = @CompID

); GO

PRINT 'Function [udf_GetComponentParams] created.'; GO

/* =============================================

93

3. MULTI-STATEMENT TABLE-VALUED FUNCTION (Сложная табличная)

Тип: Multi-Statement (создает переменную-таблицу @ret)

Задача: "Досье" на компонент. Анализирует качество заполнения данных.

Требование: "табличная, которая создается"

============================================= */

IF OBJECT_ID('[Stock].[udf_GetComponentQualityReport]', 'TF') IS NOT NULL DROP FUNCTION [Stock].[udf_GetComponentQualityReport];

GO

CREATE FUNCTION [Stock].[udf_GetComponentQualityReport]

(

@CategoryID INT -- Фильтр по категории

)

RETURNS @ReportTable TABLE

(

PartNumber NVARCHAR(100),

Manufacturer NVARCHAR(100),

HasDescription BIT,

HasModel BIT,

QualityScore INT, -- Вычисляемый балл (0-100) Verdict NVARCHAR(50)

)

AS

BEGIN

-- 1. Первичная вставка данных

94

INSERT INTO @ReportTable (PartNumber, Manufacturer,

HasDescription, HasModel, QualityScore, Verdict)

SELECT c.PartNumber, m.Name,

CASE WHEN c.Description IS NOT NULL THEN 1 ELSE 0

END,

CASE WHEN EXISTS(SELECT 1 FROM [Stock].[ComponentModels] cm WHERE cm.ComponentID = c.ComponentID) THEN 1 ELSE 0 END,

0, -- Начальный балл

'Unknown'

FROM [Stock].[Components] c

JOIN [Ref].[Manufacturers] m ON c.ManufacturerID = m.ManufacturerID

WHERE c.CategoryID = @CategoryID;

--2. Логика расчета баллов (Multi-step logic)

--+40 баллов, если есть описание

UPDATE @ReportTable SET QualityScore = QualityScore + 40 WHERE HasDescription = 1;

-- +60 баллов, если есть мат. модель

UPDATE @ReportTable SET QualityScore = QualityScore + 60 WHERE HasModel = 1;

-- 3. Вынесение вердикта

UPDATE @ReportTable

95

SET Verdict = CASE

WHEN QualityScore = 100 THEN 'Excellent'

WHEN QualityScore >= 40 THEN 'Good'

ELSE 'Poor Data'

END;

RETURN;

END

GO

PRINT 'Function [udf_GetComponentQualityReport] created.'; GO

/* =============================================

4. VIEW 1: REPORT (Для отчетов и XML)

Обычное соединение таблиц (INNER JOIN)

Имена полей на английском (для совместимости с процедурой экспорта)

============================================= */

IF OBJECT_ID('[Stock].[v_FullComponentReport]', 'V') IS NOT

NULL DROP VIEW [Stock].[v_FullComponentReport];

GO

CREATE VIEW [Stock].[v_FullComponentReport]

AS

SELECT c.ComponentID,

c.PartNumber, -- В XML уйдет как @Article m.Name AS Manufacturer,

cat.Name AS Category,

96

p.Name AS Package, c.Description, CASE

WHEN c.IsActive = 1 THEN 'Active'

ELSE 'Obsolete'

END AS Status

FROM [Stock].[Components] c

INNER JOIN [Ref].[Manufacturers] m ON c.ManufacturerID = m.ManufacturerID

INNER JOIN [Ref].[Categories] cat ON c.CategoryID = cat.CategoryID

INNER JOIN [Ref].[PackageTypes] p ON c.PackageID = p.PackageID;

GO

PRINT 'View [v_FullComponentReport] created.'; GO

/* =============================================

5. VIEW 2: ENGINEERING FILTER (Инженерный фильтр)

Фильтрация + JOIN

============================================= */

IF OBJECT_ID('[Stock].[v_ActiveComponentsSpiceready]', 'V') IS NOT NULL DROP VIEW [Stock].[v_ActiveComponentsSpiceready];

GO

CREATE VIEW [Stock].[v_ActiveComponentsSpiceready]

AS

SELECT

97

c.PartNumber, cat.Name AS Category,

m.Name AS Manufacturer, sim.Name AS SimulationType, sim.Engine

FROM [Stock].[Components] c

INNER JOIN [Stock].[ComponentModels] cm ON c.ComponentID = cm.ComponentID

INNER JOIN [Ref].[SimulationTypes] sim ON cm.SimTypeID = sim.SimTypeID

JOIN [Ref].[Categories] cat ON c.CategoryID = cat.CategoryID JOIN [Ref].[Manufacturers] m ON c.ManufacturerID = m.ManufacturerID

WHERE

c.IsActive = 1

AND sim.Name LIKE '%SPICE%';

GO

PRINT 'View [v_ActiveComponentsSpiceready] created.'; GO

/* =============================================

6. VIEW 3: ANALYTICS (Сложная аналитика)

Требование: "CTE, GROUP BY, HAVING"

Смысл: Показывает категории, где более 0 компонентов,

и считает сколько активных позиций.

============================================= */

IF OBJECT_ID('[Stock].[v_CategoryAnalytics]', 'V') IS NOT

NULL DROP VIEW [Stock].[v_CategoryAnalytics];

GO

98

CREATE VIEW [Stock].[v_CategoryAnalytics]

AS

WITH CategoryCountsCTE AS (

-- Common Table Expression для предварительного подсчета

SELECT

CategoryID,

COUNT(*) AS TotalCount,

SUM(CASE WHEN IsActive = 1 THEN 1 ELSE 0 END) AS

ActiveCount

FROM [Stock].[Components]

GROUP BY CategoryID

)

SELECT

cat.Name AS CategoryName, cte.TotalCount, cte.ActiveCount,

-- Вычисляем процент активных

CAST((cte.ActiveCount * 100.0 / cte.TotalCount) AS DECIMAL(5,2)) AS ActivePercent

FROM CategoryCountsCTE cte

JOIN [Ref].[Categories] cat ON cte.CategoryID = cat.CategoryID

-- Требование: HAVING (фильтруем группы уже после агрегации,

хотя здесь CTE, но смысл тот же)

-- Для демонстрации HAVING добавим условие: показать только те, где есть хоть 1 компонент

WHERE cte.TotalCount > 0;

GO

99

PRINT 'View [v_CategoryAnalytics] created.';

GO

PRINT '=========================================================== ==';

PRINT 'Скрипт 04 выполнен успешно.';

PRINT 'Время завершения: ' + CONVERT(VARCHAR(30), GETDATE(), 120);

PRINT '=========================================================== ==';

GO

100

Соседние файлы в папке курсач