我正在使用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
你会如何通过内部联接,表格中的列来命名?
答案 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';
我真的希望它有所帮助。
亲切的问候, 胜者。