有效地插入多级父子表

时间:2012-03-26 05:42:27

标签: sql-server-2008 stored-procedures insert parent

我有以下数据样本要插入到表格中(从父级到子级,所有多对一关系):程序,模块,类和成员。每个表使用自动标识作为主键。这适用于SQL Server 2008。

Program Module  Class   Member
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

我是否必须将其分解为多个存储过程(首先插入Program表,然后插入Module等),或者可以使用更简单,更有效的方法?

1 个答案:

答案 0 :(得分:1)

表定义:

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;

另见

编辑:我重写了整个答案,因为它不正确。