Reputation: 1922
Im trying to automate the process of bulk importing CSV files into sql-server, so far i have this:
----Allow for SQL to use cmd shell
--EXEC sp_configure 'show advanced options', 1 -- To allow advanced options to be changed.
--RECONFIGURE -- To update the currently configured value for advanced options.
--EXEC sp_configure 'xp_cmdshell', 1 -- To enable the feature.
--RECONFIGURE -- To update the currently configured value for this feature.
SET NOCOUNT ON
--Loop through all of the files
CREATE TABLE #tmp(excelFileName VARCHAR(100));
CREATE TABLE #tmpCol(col NVARCHAR(MAX));
INSERT INTO #tmp
EXEC xp_cmdshell 'dir /B "C:\Users\owain.esau\OneDrive\Work\Companies\IronSude\backupFiles\"';
DECLARE @fileName varchar(100)
DECLARE @tableName varchar(MAX)
DECLARE @sql varchar(MAX)
While (Select Count(*) From #tmp where excelFileName is not null) > 0
Begin
Select Top 1 @fileName = excelFileName From #tmp
SET @sql = 'BULK INSERT #tmpCol FROM "C:\Users\owain.esau\OneDrive\Work\Companies\IronSide\backupFiles\' + @filename + '" WITH (ROWTERMINATOR = '','', LASTROW = 1)'
EXEC (@sql)
UPDATE #tmpCol SET col = REPLACE(col, '"', '')
UPDATE #tmpCol SET col = REPLACE(col, ' ', '')
SET @tableName = LEFT(@filename, LEN(@filename) -4)
CREATE TABLE @tableNAme ( )
Delete from #tmp Where excelFileName = @FileName
End
DROP TABLE #tmp
DROP TABLE #tmpCol
The @sql
bulk insert gets the column headers as required, but i cant figure out how to actually pass this into the CREATE TABLE
statement.
Any help would be much appreciated!
----- EDIT ---------------------------------------------------
After changing CREATE TABLE to use dynamic SQL i end up with the following (i also put it into a loop):
----Allow for SQL to use cmd shell
--EXEC sp_configure 'show advanced options', 1 -- To allow advanced options to be changed.
--RECONFIGURE -- To update the currently configured value for advanced options.
--EXEC sp_configure 'xp_cmdshell', 1 -- To enable the feature.
--RECONFIGURE -- To update the currently configured value for this feature.
SET NOCOUNT ON
--Loop through all of the files
CREATE TABLE #tmp(excelFileName VARCHAR(100));
CREATE TABLE #tmpCol(col NVARCHAR(MAX));
INSERT INTO #tmp
EXEC xp_cmdshell 'dir /B "C:\Users\owain.esau\OneDrive\Work\Companies\IronSude\backupFiles\"';
DECLARE @fileName varchar(100)
DECLARE @tableName varchar(MAX)
DECLARE @colName varchar(MAX)
DECLARE @sql varchar(MAX)
DECLARE @sql2 varchar(max)
While (Select Count(*) From #tmp where excelFileName is not null) > 0
Begin
Select Top 1 @fileName = excelFileName From #tmp
SET @sql = 'BULK INSERT #tmpCol FROM "C:\Users\owain.esau\OneDrive\Work\Companies\IronSude\backupFiles\' + @filename + '" WITH (ROWTERMINATOR = '','', LASTROW = 1)'
EXEC (@sql)
UPDATE #tmpCol SET col = REPLACE(col, '"', '')
UPDATE #tmpCol SET col = REPLACE(col, ' ', '')
WHILE (SELECT COUNT(*) FROM #tmpCol WHERE col IS NOT NULL) > 0
BEGIN
Select Top 1 @colName = col From #tmpCol
SET @tableName = LEFT(@filename, LEN(@filename) - 5)
SET @sql2 = 'CREATE TABLE [' + @tableName + ']('
SELECT @sql2 = @sql2 + '[' + col + '],' FROM #tmpCol
SET @sql2 = SUBSTRING(@sql2,1,LEN(@sql2) -1) + 'NVARCHAR(MAX)) '
EXEC(@sql2)
DELETE FROM #tmpCol WHERE col = @colName
END
Delete from #tmp Where excelFileName = @FileName
End
DROP TABLE #tmp
DROP TABLE #tmpCol
The issue is, is the first Dynamic SQL query:
SET @sql = 'BULK INSERT #tmpCol FROM "C:\Users\owain.esau\OneDrive\Work\Companies\IronSude\backupFiles\' + @filename + '" WITH (ROWTERMINATOR = '','', LASTROW = 1)'
Since the last row is set to 1 and the rowterminator is ',' It only picks up one column. If i change the RowTerminator to '\n' It puts it all in one line like:
"Attachment Id","Attachment Owner Id","Modified By","Created By","Created Time","Modified Time","File Name",Size,"Parent Id","Attachment Type",Documents
Is there anyway i can set the LASTROW = the first instance of '\n'?
Upvotes: 4
Views: 691
Reputation: 37313
You can use Dynamic SQL to achieve this:
SET @tableName = LEFT(@filename, LEN(@filename) -4)
DECLARE @strQuery VARCHAR(MAX)
SET @strQuery = 'CREATE TABLE [' + @tableName + ']('
SELECT @strQuery = @strQuery + '[' + col + '],' FROM #tmpCol
SET @strQuery = SUBSTRING(@strQuery,1,LEN(@strQuery) -1) + ') '
--If you want to execute the create table query
EXEC(@strQuery)
Delete from #tmp Where excelFileName = @FileName
String Split Function
CREATE FUNCTION [dbo].[Split]
(
@String NVARCHAR(4000),
@Delimiter NCHAR(1)
)
RETURNS TABLE
AS
RETURN
(
WITH Split(stpos,endpos)
AS(
SELECT 0 AS stpos, CHARINDEX(@Delimiter,@String) AS endpos
UNION ALL
SELECT endpos+1, CHARINDEX(@Delimiter,@String,endpos+1)
FROM Split
WHERE endpos > 0
)
SELECT
'Col' = SUBSTRING(@String,stpos,COALESCE(NULLIF(endpos,0),LEN(@String)+1)-stpos)
FROM Split
)
GO
You can try splitting the columns row using a split function instead of using rowterminator = ','
, you need to add one more step. Is to pass the comma seperated string (assign it to a variable first) you provided i your question, to the function above.
Function Reference
Upvotes: 2
Reputation: 537
First construct a string with the columns and the DataType and remove the last "," by using LEFT and LEN, use this string inside the dynamic query string to create the dynamic table that you want
Declare @Columnslist varchar(max)
SELECT @Columnslist = select COLUMN_NAME+' NVARCHAR(MAX),' from TABLE_NAME for xml path('')
SELECT @Columnslist = LEFT(@Columnslist, LEN(@Columnslist) - 1)
Declare @create_cmd varchar(max)
set @create_cmd=
'If Object_id('+char(39)+@tableName+char(39)+') is Not NULL
Drop Table '+@tableName+' Create table '+@tableName+'('+@Columnslist+')'
EXEC(@create_cmd);
Upvotes: 2