代码之家  ›  专栏  ›  技术社区  ›  Reddspark

动态数据映射的存储过程

  •  6
  • Reddspark  · 技术社区  · 8 年前

    我知道这一定已经解决了,但我很难找到解决办法。我试过在google和这里搜索:存储过程动态数据映射插入映射表。

    我有一个数据映射表,上面写着

    "OriginalColumn","OriginalTable","NewColumn","NewTable"
    

    由于列名称表明该表将包含如何将一个表中的数据加载到另一个现有表中的元数据。

    我想编写一个存储过程,它将发出

    select *  
    from DataMapping 
    where OriginalTable = XXXX 
    

    然后使用它得到的信息动态地创建和执行 Insert into NewTable 基于 OriginalColumn 到 NewColumn 地图绘制。


    下面是生成示例问题的代码:

    /****** Object:  Table [dbo].[DataMapping]    Script Date: 7/23/2018 11:34:11 AM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[DataMapping](
        [OriginalColumn] [sysname] NOT NULL,
        [OriginalTable] [sysname] NOT NULL,
        [NewColumn] [sysname] NOT NULL,
        [NewTable] [sysname] NOT NULL
    ) ON [PRIMARY]
    GO
    /****** Object:  Table [dbo].[destinationTable]    Script Date: 7/23/2018 11:34:12 AM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[destinationTable](
        [id] [int] NULL,
        [field1] [nvarchar](50) NULL,
        [field2] [nvarchar](50) NULL
    ) ON [PRIMARY]
    GO
    /****** Object:  Table [dbo].[TableA]    Script Date: 7/23/2018 11:34:12 AM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[TableA](
        [sourceID] [int] NULL,
        [sourceField1] [nchar](10) NULL,
        [sourceField2] [nvarchar](50) NULL
    ) ON [PRIMARY]
    GO
    /****** Object:  Table [dbo].[TableB]    Script Date: 7/23/2018 11:34:12 AM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[TableB](
        [sourceID] [int] NULL,
        [sourceField1] [nchar](10) NULL,
        [sourceField2] [nvarchar](50) NULL
    ) ON [PRIMARY]
    GO
    INSERT [dbo].[DataMapping] ([OriginalColumn], [OriginalTable], [NewColumn], [NewTable]) VALUES (N'sourceField1', N'TableA', N'field1', N'DestinationTable')
    GO
    INSERT [dbo].[DataMapping] ([OriginalColumn], [OriginalTable], [NewColumn], [NewTable]) VALUES (N'sourceField2', N'TableA', N'field2', N'DestinationTable')
    GO
    INSERT [dbo].[DataMapping] ([OriginalColumn], [OriginalTable], [NewColumn], [NewTable]) VALUES (N'sourceID', N'TableA', N'id', N'DestinationTable')
    GO
    INSERT [dbo].[DataMapping] ([OriginalColumn], [OriginalTable], [NewColumn], [NewTable]) VALUES (N'sourceField1', N'TableB', N'field1', N'DestinationTable')
    GO
    INSERT [dbo].[DataMapping] ([OriginalColumn], [OriginalTable], [NewColumn], [NewTable]) VALUES (N'sourceField2', N'TableB', N'field2', N'DestinationTable')
    GO
    INSERT [dbo].[DataMapping] ([OriginalColumn], [OriginalTable], [NewColumn], [NewTable]) VALUES (N'sourceID', N'TableB', N'id', N'DestinationTable')
    GO
    INSERT [dbo].[destinationTable] ([id], [field1], [field2]) VALUES (NULL, N'col1      ', NULL)
    GO
    INSERT [dbo].[destinationTable] ([id], [field1], [field2]) VALUES (NULL, N'col2      ', NULL)
    GO
    INSERT [dbo].[destinationTable] ([id], [field1], [field2]) VALUES (NULL, N'col1      ', N'12345ABC')
    GO
    INSERT [dbo].[destinationTable] ([id], [field1], [field2]) VALUES (NULL, N'col2      ', N'24681DEF')
    GO
    INSERT [dbo].[destinationTable] ([id], [field1], [field2]) VALUES (1, N'col1      ', N'12345ABC')
    GO
    INSERT [dbo].[destinationTable] ([id], [field1], [field2]) VALUES (2, N'col2      ', N'24681DEF')
    GO
    INSERT [dbo].[TableA] ([sourceID], [sourceField1], [sourceField2]) VALUES (1, N'col1      ', N'12345ABC')
    GO
    INSERT [dbo].[TableA] ([sourceID], [sourceField1], [sourceField2]) VALUES (2, N'col2      ', N'24681DEF')
    GO
    INSERT [dbo].[TableB] ([sourceID], [sourceField1], [sourceField2]) VALUES (2, N'B1234     ', N'9999')
    GO
    INSERT [dbo].[TableB] ([sourceID], [sourceField1], [sourceField2]) VALUES (2, N'B5678     ', N'9999')
    GO
    

    最终解决方案

    下面是最后一个解决方案,在这个解决方案中,我选择了下面的最佳答案,并将其转换为一个存储过程,允许我们选择要填充的目标表,以防您不想重新运行整个导入过程。

    CREATE PROCEDURE [dbo].[DataMappingProc2]
    (
    @DestinationTable as VARCHAR(40)
    )
    AS 
        BEGIN
        DECLARE @Sql nvarchar(max) = ''
    
        SELECT @Sql += 'INSERT INTO '+ NewTable +'(' + 
                STUFF((SELECT ', ' + NewColumn
                       FROM dbo.DataMapping t1
                       WHERE t1.NewTable = t0.NewTable
                       AND t1.OriginalTable = t0.OriginalTable
                       And t1.NewTable = @DestinationTable
                       ORDER BY NewColumn
                       FOR XML PATH('')), 1, 2, '') +') ' + 
                'SELECT '+ 
                STUFF((SELECT ', ' + OriginalColumn
                       FROM dbo.DataMapping t2
                       WHERE t2.NewTable = t0.NewTable
                       AND t2.OriginalTable = t0.OriginalTable
                       And t2.NewTable = @DestinationTable
                       ORDER BY NewColumn
                       FOR XML PATH('')), 1, 2, '') +' FROM '+ OriginalTable +'; '
        FROM dbo.DataMapping t0
        WHERE t0.NewTable = @DestinationTable
        GROUP BY NewTable, OriginalTable
    
        EXEC (@Sql)
    
        Return 0
        END
    GO
    

    运行存储过程

    DECLARE @return_value int
    EXEC    @return_value = [dbo].[DataMappingProc2]
            @DestinationTable = N'DestinationTable'
    
    SELECT  'Return Value' = @return_value
    GO
    
    3 回复  |  直到 8 年前
        1
  •  2
  •   Zohar Peled    8 年前

    更新: 在写我的原始答案时,我错误地假设每对表和列之间会有一个唯一的映射(如果原始问题包含了它现在包含的示例数据,那么假设就可以避免了),因此我的答案是错误的。

    现在,问题已更新为包含正确的示例数据,我可以更新我的答案-通过向子查询添加另一个条件,并向原始查询添加一个group by,我已设法获得一个工作解决方案:

    DECLARE @Sql nvarchar(max) = ''
    
    SELECT @Sql += 'INSERT INTO '+ NewTable +'(' + 
            STUFF((SELECT ', ' + NewColumn
                   FROM dbo.DataMapping t1
                   WHERE t1.NewTable = t0.NewTable
                   AND t1.OriginalTable = t0.OriginalTable
                   ORDER BY NewColumn
                   FOR XML PATH('')), 1, 2, '') +') ' + 
            'SELECT '+ 
            STUFF((SELECT ', ' + OriginalColumn
                   FROM dbo.DataMapping t2
                   WHERE t2.NewTable = t0.NewTable
                   AND t2.OriginalTable = t0.OriginalTable
                   ORDER BY NewColumn
                   FOR XML PATH('')), 1, 2, '') +' FROM '+ OriginalTable +'; '
    FROM dbo.DataMapping t0  
    GROUP BY NewTable, OriginalTable
    

    Updated rextster link

    第一个版本

    下面是一个不需要使用游标的解决方案:

    DECLARE @Sql nvarchar(max) = ''
    
    SELECT @Sql += 'INSERT INTO '+ NewTable +'(' + 
            STUFF((SELECT ', ' + NewColumn
                   FROM dbo.DataMapping t1
                   WHERE t1.NewTable = t0.NewTable
                   ORDER BY NewColumn
                   FOR XML PATH('')), 1, 2, '') +') ' + 
            'SELECT '+ 
            STUFF((SELECT ', ' + OriginalColumn
                   FROM dbo.DataMapping t2
                   WHERE t2.NewTable = t0.NewTable
                   ORDER BY NewColumn
                   FOR XML PATH('')), 1, 2, '') +' FROM '+ OriginalTable +'; '
    FROM dbo.DataMapping t0  
    
    EXEC (@Sql)
    

    你可以看到 live demo on rextester 多亏了M.Ali的样本数据。

        2
  •  0
  •   M.Ali    8 年前

    样本数据

    CREATE TABLE dbo.DataMapping (   OriginalColumn     SYSNAME
                                    ,OriginalTable      SYSNAME
                                    ,NewColumn          SYSNAME
                                    ,NewTable           SYSNAME)
    
    INSERT INTO dbo.DataMapping
    (   OriginalColumn
      , OriginalTable
      , NewColumn
      , NewTable)
    VALUES 
        (   'Col1' , 'TableA' , 'Col_1' , 'TableAN') ,  (   'Col2' , 'TableA' , 'Col_2' , 'TableAN') 
      , (   'Col3' , 'TableA' , 'Col_3' , 'TableAN') ,  (   'Col1' , 'TableB' , 'Col_1' , 'TableBN') 
      , (   'Col2' , 'TableB' , 'Col_2' , 'TableBN') , (   'Col3' , 'TableB' , 'Col_3' , 'TableBN'); 
    

    查询

    Declare   @O_Cols           sysname
            , @N_Cols           sysname
            , @O_Tabl           sysname
            , @N_Tabl           sysname
            , @InsertColsList   NVARCHAR(MAX) =''
            , @SelectColsLIst   NVARCHAR(MAX) =''
            , @Sql              NVARCHAR(MAX);
    
    DECLARE Cur CURSOR LOCAL FAST_FORWARD FOR
    SELECT OriginalColumn , NewColumn
    FROM dbo.DataMapping
    WHERE OriginalTable = 'TableA'
    
    
    OPEN Cur
    
     FETCH NEXT FROM Cur INTO @O_Cols , @N_Cols
    
    WHILE (@@FETCH_STATUS = 0)
    BEGIN
            SET @SelectColsLIst += ISNULL(',' + QUOTENAME(@O_Cols), '');
            SET @InsertColsList += ISNULL(',' + QUOTENAME(@N_Cols), '');
    
        FETCH NEXT FROM Cur INTO @O_Cols , @N_Cols
    END
    
    CLOSE Cur
    DEALLOCATE Cur;
    
        SET @SelectColsLIst = STUFF(@SelectColsLIst, 1 ,1,'');
        SET @InsertColsList = STUFF(@InsertColsList, 1 ,1,'');
    
    
    SELECT TOP 1  @O_Tabl = OriginalTable ,  @N_Tabl = NewTable 
    FROM dbo.DataMapping
    WHERE OriginalTable = 'TableA'
    
     SET @Sql = N' INSERT INTO ' + @N_Tabl + N'( ' + @InsertColsList + N' )'
              + N' SELECT ' + @SelectColsLIst
              + N' FROM ' + @O_Tabl;
    
    
    PRINT @Sql 
    --EXEC sp_executesql @Sql;
    

    注意

    我假设数据只来自一个表,只流向一个表,源表和目标表的列名可能不同,表名可能不同,但总是一对一的映射。

        3
  •  0
  •   Reddspark    8 年前

    我最终选择了佐哈尔的解决方案,但是我非常喜欢阿里的解决方案。下面是我如何将m ali的解决方案修改为一个存储过程,以便可以针对不同的源表多次调用它。

    zohar的解决方案也可以调整为只处理特定的表,但就我现在的目的而言,它还不错。

    CREATE PROCEDURE [dbo].[DataMappingProc]
    (
    @Tblname as VARCHAR(10)
    )
    AS 
        BEGIN
    
        Declare   @O_Cols           sysname
                , @N_Cols           sysname
                , @O_Tabl           sysname
                , @N_Tabl           sysname
                , @InsertColsList   NVARCHAR(MAX) =''
                , @SelectColsLIst   NVARCHAR(MAX) =''
                , @Sql              NVARCHAR(MAX);
    
    
        DECLARE Cur CURSOR LOCAL FAST_FORWARD FOR
        SELECT OriginalColumn , NewColumn
        FROM dbo.DataMapping
        WHERE OriginalTable = @Tblname
    
        OPEN Cur
    
         FETCH NEXT FROM Cur INTO @O_Cols , @N_Cols
    
        WHILE (@@FETCH_STATUS = 0)
        BEGIN
                SET @SelectColsLIst += ISNULL(',' + QUOTENAME(@O_Cols), '');
                SET @InsertColsList += ISNULL(',' + QUOTENAME(@N_Cols), '');
    
            FETCH NEXT FROM Cur INTO @O_Cols , @N_Cols
        END
    
        CLOSE Cur
        DEALLOCATE Cur;
    
            SET @SelectColsLIst = STUFF(@SelectColsLIst, 1 ,1,'');
            SET @InsertColsList = STUFF(@InsertColsList, 1 ,1,'');
    
    
        SELECT TOP 1  @O_Tabl = OriginalTable ,  @N_Tabl = NewTable 
        FROM dbo.DataMapping
        WHERE OriginalTable = 'TableA'
    
         SET @Sql = N' INSERT INTO ' + @N_Tabl + N'( ' + @InsertColsList + N' )'
                  + N' SELECT ' + @SelectColsLIst
                  + N' FROM ' + @O_Tabl;
    
    
        EXEC sp_executesql @Sql;
        RETURN 0
        END;
    GO
    
    推荐文章