繁体   English   中英

以更改列的顺序从csv导入sql

[英]Importing to sql from csv in changing order of columns

我正在使用SQL2012。我想在SQL中创建一个存储过程,该过程将删除一个表,然后基于从csv文件的导入创建一个表。 到目前为止足够简单。

问题是由于某些我无法控制的问题,CSV文件中的列可能会按顺序更改。 我计划使用与表中的另一个名称链接的名称来标识列(同样,这也是我无法控制的)。

例如(以CSV格式):

Name1           Name2      Name3
1                3           2
22               4           3
3                13          12
41               8           1
22               6           4

在元数据表中:

Names         ID      
Name1         ID1           
Name2         ID2           
Name3         ID3         

我想通过导入创建的表:

ID1           ID2      ID3
1             3         2
22            4         3
3             13        12
41            8         1
22            6         4

问题是列的名称不一定总是相同的顺序,在任何给定的一天,我都可以得到一个类似于以下内容的CSV:

Name3         Name2        Name1
2               3           1
3               4           22
12              13          3
1               8           41
4               6           22

您将如何通过内部联接(表中的列)进行命名?

这有一些假设:总是3列,所有数据都是int类型,目标表是静态的,等等。如果您的需求更加复杂,则可以开始使用专用的ETL工具。

CREATE PROCEDURE Import (
  @filename varchar(max)
) AS
BEGIN
  DECLARE @sql nvarchar(max)
  DECLARE @columns_i nvarchar(max)
  DECLARE @columns_o nvarchar(max)

  CREATE TABLE #header ([1] sysname, [2] sysname, [3] sysname)
  SET @sql = N'BULK INSERT #header FROM ' + QUOTENAME(@filename) + ' WITH (DATAFILETYPE = ''char'',FIELDTERMINATOR = '','',ROWTERMINATOR = ''0x0D0A'',FIRSTROW = 1, LASTROW = 1);'
  EXEC sp_executesql @sql

  SELECT @columns_i = ISNULL(@columns_i+',','') + QUOTENAME([column]) + ' int' FROM #header UNPIVOT([column] FOR [colnum] IN ([1],[2],[3])) p ORDER BY [colnum]
  SELECT @columns_o = ISNULL(@columns_o+',','') + QUOTENAME([Names] + ' AS ' + QUOTENAME([ID]) FROM MyMetadata ORDER BY [Names]

  SET @sql = N'CREATE TABLE #data ('+@columns_i+');'
  SET @sql = @sql + N'BULK INSERT #data FROM ' + QUOTENAME(@filename) + ' WITH (DATAFILETYPE = ''char'',FIELDTERMINATOR = '','',ROWTERMINATOR = ''0x0D0A'',FIRSTROW = 2);'
  SET @sql = @sql + N'SELECT '+@columns_o+' FROM #data'

  INSERT MyDestination
  EXEC sp_executesql @sql
END

使用的表结构:

create table mapTable(
    inCsv varchar(max),
    inSql varchar(max)
);

create table csvImported(
    Name1 int,
    Name2 int,
    Name3 int
);

在这里,假设您已经有一个导入了csv数据的表。 因此,为了进行测试,在csvImported表中填充了一些内容。 地图表,一样。

填充mapTable表;

insert into mapTable values ('Name1', 'ID');
insert into mapTable values ('Name2', 'ID2');
insert into mapTable values ('Name3', 'ID3');

填充csvImported表;

insert into csvImported values (11, 122, 333);
insert into csvImported values (110, 1422, 37833);
insert into csvImported values (101, 1252, 33213);

因此,这是过程定义。

CREATE PROCEDURE CREATE_TABLE_FROM_CSV(
    @CsvTableName varchar(max),
    @WantedTableName varchar(max)

) AS

SET NOCOUNT ON;

DECLARE @vColumnList            varchar(max) = '',
        @vColumnName            varchar(max) = '',
        @vColumnNameRenamed     varchar(max) = '',
        @vColumns               TinyInt = 0,
        @vTableNameInSql        varchar(max) = @WantedTableName,
        @vTableNameInCsv        varchar(max) = @CsvTableName,
        @vDoCreateTable         varchar(max) = '';

        if ((select OBJECT_ID('ShadowMapTable')) > 0 ) 
        begin 
            drop table ShadowMapTable;
        end;    

        select * into ShadowMapTable from mapTable;

        select      t1.name
        from        sys.columns t1 
        join        sys.tables t2 on (t1.object_id = t2.object_id)
        join        ShadowMapTable t3 on (t1.name = t3.inCsv)
        where       t2.name = @vTableNameInCsv;

        set @vColumns = @@rowcount;

        WHILE (@vColumns > 0)
        begin
            select      @vColumnName = t1.name, @vColumnNameRenamed = t1.name + ' as ' + t3.inSql
            from        sys.columns t1 
            join        sys.tables t2 on (t1.object_id = t2.object_id)
            join        ShadowMapTable t3 on (t1.name = t3.inCsv)
            where       t2.name = @vTableNameInCsv

            -- Define the ColumnListRenamed -> used in the into clause.
            if (@vColumnList = '')
            begin 
                set @vColumnList = @vColumnNameRenamed
            end else
            begin
                set @vColumnList = @vColumnNameRenamed + ',' + @vColumnList;
            end;

            delete from ShadowMapTable
            where       inCsv = @vColumnName

            select      t1.name, t3.inCsv, t3.inSql
            from        sys.columns t1 
            join        sys.tables t2 on (t1.object_id = t2.object_id)
            join        ShadowMapTable t3 on (t1.name = t3.inCsv )
            where       t2.name = @vTableNameInCsv

            set @vColumns = @@rowcount;
        end;

        set @vDoCreateTable = '
                                if((select object_id('''+@vTableNameInSql+''')) > 0) 
                                begin 
                                    drop table '+@vTableNameInSql+'; 
                                end; 

                                select ' + @vColumnList + ' into ' + @vTableNameInSql + ' from ' + @vTableNameInCsv + ';';
        --print @vDoCreateTable;
        exec    (@vDoCreateTable);
        exec    ('select * from ' + @vTableNameInSql);
        print   ('Table created: ' + @vTableNameInSql);

最后,您应该如何调用Proc。

exec CREATE_TABLE_FROM_CSV 'csvImported', 'wantedTableName';

我真的希望能对您有所帮助。

此致,维克多。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM