[英]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.