在更改列的顺序时从csv导入到sql

时间:2014-01-22 18:18:01

标签: sql sql-server csv import multiple-columns

我正在使用SQL 2012.我想在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

你会如何通过内部联接,表格中的列来命名?

2 个答案:

答案 0 :(得分:0)

这做了一些假设:总是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

答案 1 :(得分:0)

使用的表格结构:

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';

我真的希望它有所帮助。

亲切的问候, 胜者。