Таблица определений:
CREATE TABLE Programs (
ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
Name varchar(50)
);
CREATE TABLE Modules (
ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
ProgramID INT,
Name varchar(50)
);
CREATE TABLE Classes (
ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
ModuleID INT,
Name varchar(50)
);
CREATE TABLE Functions (
ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
ClassID INT,
Name varchar(50)
);
Определение типа:
CREATE TYPE ProgramTableType AS TABLE
(
Program varchar(50),
Module varchar(50),
Class varchar(50),
Func varchar(50)
);
Определение процедуры:
CREATE PROCEDURE dbo.sp_insert_definitions
@NewRows ProgramTableType READONLY
AS
SET NOCOUNT ON;
DECLARE cur_new CURSOR FOR
SELECT Program, Module, Class, Func
FROM @NewRows
ORDER BY Program, Module, Class, Func;
DECLARE
-- Cache variables
@ProgramID int,
@ProgramName varchar(50) = NULL,
@ModuleID int,
@ModuleName varchar(50) = NULL,
@ClassID int,
@ClassName varchar(50) = NULL,
-- Iteration variables
@Program varchar(50),
@Module varchar(50),
@Class varchar(50),
@Func varchar(50);
OPEN cur_new;
FETCH NEXT FROM cur_new
INTO @Program, @Module, @Class, @Func;
-- Loop trough the cursor
WHILE @@FETCH_STATUS = 0
BEGIN
-- Get or create program
IF @ProgramName IS NULL OR @Program <> @ProgramName
BEGIN
IF NOT EXISTS (SELECT NULL FROM Programs WHERE Name = @Program)
INSERT INTO Programs (Name)
VALUES (@Program);
SELECT
@ProgramID = ID,
@ProgramName = Name,
@ModuleID = NULL,
@ModuleName = NULL,
@ClassID = NULL,
@ClassName = NULL
FROM Programs
WHERE Name = @Program;
END
-- Get or create module
IF @ModuleName IS NULL OR @Module <> @ModuleName
BEGIN
IF NOT EXISTS (SELECT NULL FROM Modules WHERE Name = @Module AND ProgramID = @ProgramID)
INSERT INTO Modules (ProgramID, Name)
VALUES (@ProgramID, @Module);
SELECT
@ModuleID = ID,
@ModuleName = Name,
@ClassID = NULL,
@ClassName = NULL
FROM Modules
WHERE Name = @Module
AND ProgramID = @ProgramID;
END;
-- Get or create class
IF @ClassName IS NULL OR @Class <> @ClassName
BEGIN
IF NOT EXISTS (SELECT NULL FROM Classes WHERE Name = @Class AND ModuleID = @ModuleID)
INSERT INTO Classes (ModuleID, Name)
VALUES (@ModuleID, @Class);
SELECT
@ClassID = ID,
@ClassName = Name
FROM Classes
WHERE Name = @Class
AND ModuleID = @ModuleID;
END;
-- Create function if it doesn't exists
IF NOT EXISTS (SELECT NULL FROM Functions WHERE Name = @Func AND ClassID = @ClassID)
INSERT INTO Functions (ClassID, Name)
VALUES (@ClassID, @Func);
FETCH NEXT FROM cur_new
INTO @Program, @Module, @Class, @Func;
END
CLOSE cur_new;
DEALLOCATE cur_new;
GO
Пример:
BEGIN TRAN;
DECLARE @NewData AS ProgramTableType;
INSERT INTO @NewData (Program, Module, Class, Func)
VALUES ('Program1', 'M1', 'C1', 'Func1'),
('Program1', 'M1', 'C1', 'Func2'),
('Program1', 'M1', 'C2', 'Func3'),
('Program1', 'M2', 'C3', 'Func4'),
('Program1', 'M2', 'C4', 'Func5'),
('Program2', 'M3', 'C5', 'Func6'),
('Program2', 'M3', 'C5', 'Func7'),
('Program2', 'M3', 'C6', 'Func8'),
('Program2', 'M4', 'C7', 'Func9'),
('Program2', 'M4', 'C7', 'Func10'),
('Program2', 'M4', 'C8', 'Func11');
EXEC sp_insert_definitions @NewData;
COMMIT TRAN;
Вернуть исходный ввод:
SELECT p.Name AS Program, m.Name AS Module, c.Name AS Class, f.Name AS [Function]
FROM Functions f
INNER JOIN Classes c ON c.ID = f.ClassID
INNER JOIN Modules m ON m.ID = c.ModuleID
INNER JOIN Programs p ON p.ID = m.ProgramID;
См. Также
Редактировать: Я переписал весь ответ, так как он был неверным.