I am trying to insert data from multiple CSV files from a single folder to a single table.
I can do bulinsert for 1 file using the following code:
USE [dbname]
GO
BULK INSERT tablename
FROM 'path to csv files'
WITH
(
FIRSTROW = 2, -- as 1st one is header
FIELDTERMINATOR = ',', --CSV field delimiter
ROWTERMINATOR = '\n', --Use to shift the control to next row
TABLOCK
)
GO
The first thing I would say is I personally wouldn't do this in T-SQL, I'd use something a bit better suited to the task, the SSIS Multiple flat file connection manager for example. This is possible in T-SQL but it is not the most robust approach and has limitation (such as the directories that can even be accessed).
-- Set the directory to check for files
DECLARE #Directory NVARCHAR(200) = N'C:\Your File Location\';
-- Create a table variable to store the files output from xp_dirtree
DECLARE #Files TABLE (FileName NVARCHAR(255), Depth INT, IsFile BIT);
-- Get the files from the folder
INSERT #Files(FileName, Depth, IsFile)
EXECUTE master..xp_dirtree #Directory, 1, 1;
--select the filenames and use STRING_AGG to combine into a single string to execute
DECLARE #SQL NVARCHAR(MAX) =
( SELECT STRING_AGG(CONCAT('BULK INSERT YourTableName FROM ''',
CONCAT(#Directory, f.FileName), '''
WITH (
FIELDTERMINATOR = '','',
ROWTERMINATOR = ''\n'',
FIRSTROW = 1
)'), ';' + CHAR(10))
FROM #Files AS f
WHERE f.IsFile = 1
AND f.FileName LIKE '%.csv'-- Optionally limit files
);
PRINT #SQL;
-- Uncomment below line once you're happy with the SQL Printed
--EXECUTE sp_executesql #SQL;
Or if you want a bit more control over error handling, you could use a cursor to iterate the files:
-- Set the directory to check for files
DECLARE #Directory NVARCHAR(200) = N'C:\Import Location\';
-- Create a table variable to store the files output from xp_dirtree
DECLARE #Files TABLE (FileName NVARCHAR(255), Depth INT, IsFile BIT);
-- Get the files from the folder
INSERT #Files(FileName, Depth, IsFile)
EXECUTE master..xp_dirtree #Directory, 1, 1;
--declare a cursor to loop through the files, filtered for csv
DECLARE FileCursor CURSOR LOCAL STATIC FORWARD_ONLY READ_ONLY
FOR
SELECT FilePath = CONCAT(#Directory, f.FileName)
FROM #Files AS f
WHERE f.IsFile = 1
AND f.FileName LIKE '%.csv'; -- Optionally limit files
OPEN FileCursor;
DECLARE #FilePath NVARCHAR(255);
FETCH FROM FileCursor INTO #FilePath;
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #FilePath;
DECLARE #sql NVARCHAR(MAX) =
CONCAT('BULK INSERT YourTableName FROM ''', #FilePath, '''
WITH (
FIELDTERMINATOR = '','',
ROWTERMINATOR = ''\n'',
FIRSTROW = 1
)');
BEGIN TRY
EXECUTE sp_executesql #SQL;
END TRY
BEGIN CATCH
-- Do something to handle errors
END CATCH
FETCH NEXT FROM FileCursor INTO #FilePath;
END
CLOSE FileCursor;
DEALLOCATE FileCursor;
As I say though, SSIS or another dedicated ETL tool is a better choice.
I have a folder called "Data" This folder consists of various .CSV Files with same schema. The folder Location is 'C:\Data..'
I want to Import the contents of all files recursively into SQL Server in one table.
Append additional column in the table which consists for each file.
Have tried some solutions found it here
, but it didn't work.
--get the list of files to process:
SET #path = 'C:\Data\'
SET #cmd = 'dir ' + #path + '*.csv /b'
INSERT INTO ALLFILENAMES(WHICHFILE)
EXEC Master..xp_cmdShell #cmd
UPDATE ALLFILENAMES SET WHICHPATH = #path where WHICHPATH is null
--cursor loop
declare c1 cursor for SELECT WHICHPATH,WHICHFILE FROM ALLFILENAMES where WHICHFILE like '%.csv%'
open c1
fetch next from c1 into #path,#filename
While ##fetch_status <> -1
begin
--bulk insert won't take a variable name, so make a sql and execute it instead:
set #sql = 'BULK INSERT Temp FROM ''' + #path + #filename + ''' '
+ ' WITH (
FIELDTERMINATOR = '','',
ROWTERMINATOR = ''\n'',
FIRSTROW = 2
) '
print #sql
exec (#sql)
fetch next from c1 into #path,#filename
end
close c1
deallocate c1
TWo things which aren't working as expected:
1) It doesn't work for recursive files in the directory.
2) Not able to do the bulk insert to Temp file created.
I found so many queries online to import multiple files to SQL Server into one single table from a folder like the one below but no help online on how to insert multiple different files as different tables in SQL Server. I have 21 files (21 for now, might increase with time) and its really very tedious to import each and every file from the folder.
CREATE TABLE ALLFILENAMES(WHICHPATH VARCHAR(255),WHICHFILE varchar(255))
--some variables
declare #filename varchar(255),
#path varchar(255),
#sql varchar(8000),
#cmd varchar(1000)
--get the list of files to process:
SET #path = 'C:\Users\atp1lip\Desktop\09242017\'
SET #cmd = 'dir ' + #path + '*.txt /b'
INSERT INTO ALLFILENAMES(WHICHFILE)
EXEC Master..xp_cmdShell #cmd
UPDATE ALLFILENAMES SET WHICHPATH = #path where WHICHPATH is null
--cursor loop
declare c1 cursor for SELECT WHICHPATH,WHICHFILE FROM ALLFILENAMES where WHICHFILE like '%.txt%'
open c1
fetch next from c1 into #path,#filename
While ##fetch_status <> -1
begin
set #sql = 'BULK INSERT test FROM ''' + #path + #filename + ''' '
+ ' WITH (
FIELDTERMINATOR = '','',
ROWTERMINATOR = ''\n''
) '
print #sql
exec (#sql)
fetch next from c1 into #path,#filename
end
close c1
deallocate c1
I was wondering if its possible to do this? Any help is appreciated. Thanks!
you also can use function xp_dirtree like this:
CREATE TABLE #FilesList(ID INT IDENTITY(1,1), FileName VARCHAR(1000),Depth INT,isFile INT)
INSERT INTO #FilesList
EXEC xp_dirtree #FilePath, 1, 1
I have a query to move files from one folder(Source) to another(Destination)
I have given permission on both source and destination to network services and local services, I get an error
The system cannot find the file specified
I have tested the folders to see if I am able to to access the files and I was able to, it seems when I get the files it works. It is when I try to move the files to the Destination folder, I get this error.
My query below is as follow, I create a temp table to link to my source folder and insert its contents into it, I then filter it out into another temp table, where I then get the files I want to move and then use a cursor to iterate through it and move the files.
I hope this can assist.
Create Table #tmpDir
(
ID int IDENTITY(1,1),
fName varchar(400)
)
Declare #dir varchar(100)
Declare #folderPath varchar(500)
set #folderPath = '\\Server1\Documents\Ocs\Inbox\'
set #dir = 'DIR ' + '"' + #folderPath + '"'
print #dir
INSERT #tmpDir EXECUTE master.dbo.xp_cmdshell #dir
DELETE FROM #tmpDir where ID < 6
SELECT SUBSTRING(FName,40,100) fileName2
into #THIS
FROM #tmpDir
WHERE FName not like '%<DIR>%'
and FName not like '%bytes%' and FName is not null
Delete #THIS Where fileName2 Not Like '%_MyFiles%'
Declare #FileMove varchar(100)
Declare cur cursor for
Select fileName2 From #THIS
Open cur
Fetch next from cur into #FileMove
WHILE ##FETCH_STATUS = 0
BEGIN
Declare #cmd varchar(1000)
set #cmd = 'Move /y "\\Server1\Documents\Ocs\Inbox\' + #FileMove + ' "\\Server1\ImportMac\Inbox"'
EXECUTE master.dbo.xp_cmdshell #cmd
Fetch next from cur into #FileMove
END
Close cur
Deallocate cur
Drop Table #tmpDir, #THIS
You need to put a double quote at the end of the source file name for your move command:
set #cmd = 'Move /y "\\Server1\Documents\Ocs\Inbox\' + #FileMove + '" "\\Server1\ImportMac\Inbox"'
I have a folder called "Dump." This folder consists of various .CSV Files.
The folder Location is 'C:\Dump'
I want to Import the contents of these files into SQL Server.
I want the rough code along with proper comments so that I understand it.
I have tried a few codes that I found on the Net. But they haven't quite worked out for me for some strange reason.
The steps I would like to have are
Step 1: Copy all the File Names in the folder to a Table
Step 2: Iterate through the table and copy the data from the files using Bulk Insert.
Someone do please help me out on this one. Thanks a lot in advance :)
--BULK INSERT MULTIPLE FILES From a Folder
--a table to loop thru filenames drop table ALLFILENAMES
CREATE TABLE ALLFILENAMES(WHICHPATH VARCHAR(255),WHICHFILE varchar(255))
--some variables
declare #filename varchar(255),
#path varchar(255),
#sql varchar(8000),
#cmd varchar(1000)
--get the list of files to process:
SET #path = 'C:\Dump\'
SET #cmd = 'dir ' + #path + '*.csv /b'
INSERT INTO ALLFILENAMES(WHICHFILE)
EXEC Master..xp_cmdShell #cmd
UPDATE ALLFILENAMES SET WHICHPATH = #path where WHICHPATH is null
--cursor loop
declare c1 cursor for SELECT WHICHPATH,WHICHFILE FROM ALLFILENAMES where WHICHFILE like '%.csv%'
open c1
fetch next from c1 into #path,#filename
While ##fetch_status <> -1
begin
--bulk insert won't take a variable name, so make a sql and execute it instead:
set #sql = 'BULK INSERT Temp FROM ''' + #path + #filename + ''' '
+ ' WITH (
FIELDTERMINATOR = '','',
ROWTERMINATOR = ''\n'',
FIRSTROW = 2
) '
print #sql
exec (#sql)
fetch next from c1 into #path,#filename
end
close c1
deallocate c1
--Extras
--delete from ALLFILENAMES where WHICHFILE is NULL
--select * from ALLFILENAMES
--drop table ALLFILENAMES
This will give you separate tables for each file.
--BULK INSERT MULTIPLE FILES From a Folder
drop table allfilenames
--a table to loop thru filenames drop table ALLFILENAMES
CREATE TABLE ALLFILENAMES(WHICHPATH VARCHAR(255),WHICHFILE varchar(255))
--some variables
declare #filename varchar(255),
#path varchar(255),
#sql varchar(8000),
#cmd varchar(1000)
--get the list of files to process:
SET #path = 'D:\Benihana\backup_csv_benihana_20191128032207_part_1\'
SET #cmd = 'dir ' + #path + '*.csv /b'
INSERT INTO ALLFILENAMES(WHICHFILE)
EXEC Master..xp_cmdShell #cmd
UPDATE ALLFILENAMES SET WHICHPATH = #path where WHICHPATH is null
delete from ALLFILENAMES where WHICHFILE is null
--SELECT replace(whichfile,'.csv',''),* FROM dbo.ALLFILENAMES
--cursor loop
declare c1 cursor for SELECT WHICHPATH,WHICHFILE FROM ALLFILENAMES where WHICHFILE like '%.csv%' order by WHICHFILE desc
open c1
fetch next from c1 into #path,#filename
While ##fetch_status <> -1
begin
--bulk insert won't take a variable name, so make a sql and execute it instead:
set #sql =
'select * into '+ Replace(#filename, '.csv','')+'
from openrowset(''MSDASQL''
,''Driver={Microsoft Access Text Driver (*.txt, *.csv)}''
,''select * from '+#Path+#filename+''')'
print #sql
exec (#sql)
fetch next from c1 into #path,#filename
end
close c1
deallocate c1
For Step 1 Maybe you can look at:
http://www.sql-server-performance.com/forum/threads/copying-filenames-to-sql-table.11546/
or
How to list files inside a folder with SQL Server
and then Step 2
How to cast variables in T-SQL for bulk insert?
HTH
You might need to enable the xp_cmdshell first:
sp_configure 'show advanced options', '1'
RECONFIGURE
go
sp_configure 'xp_cmdshell', '1'
RECONFIGURE
go
And, to enable ad_hoc,
sp_configure 'show advanced options', 1;
RECONFIGURE;
GO
sp_configure 'Ad Hoc Distributed Queries', 1;
RECONFIGURE;
GO
To solve step 1, xp_dirtree can also be used to list all files and folders.
Keep in mind that it is an undocumented function. Security precautions must be considered. Intentionally crafted filenames could be an intrusion vector.
In python you can use d6tstack which makes this simple
import d6tstack
import glob
c = d6tstack.combine_csv.CombinerCSV(glob.glob('*.csv'))
c.to_mssql_combine('mssql+pymssql://usr:pwd#localhost/db', 'tablename')
See SQL examples. It also deals with data schema changes, creates table and allows you to preprocess data. It leverages BULK INSERT so should be just as fast.
to expand upon the answer by SarangArd you can replace temp with the following if your file name matches your table name.
' + Left(#filename, Len(#filename)-4) + '
This code will create a new table per CSV file that is imported.
Best to populate empty database from CSV files.
CREATE TABLE ALLFILENAMES
(
WHICHPATH VARCHAR(255)
,WHICHFILE VARCHAR(255)
)
DECLARE #filename VARCHAR(255),
#path VARCHAR(255),
#sql VARCHAR(8000),
#cmd VARCHAR(1000)
SET #path = 'L:\DATA\SOURCE\CSV\' --PATH TO YOUR CSV FILES (CHANGE TO YOUR PATH)
SET #cmd = 'dir ' + #path + '*.csv /b'
INSERT INTO ALLFILENAMES(WHICHFILE)
EXEC Master..xp_cmdShell #cmd
UPDATE ALLFILENAMES
SET WHICHPATH = #path
WHERE WHICHPATH IS NULL
DECLARE c1 CURSOR
FOR SELECT WHICHPATH
,WHICHFILE
FROM ALLFILENAMES
WHERE WHICHFILE LIKE '%.csv%'
OPEN c1
FETCH NEXT FROM c1 INTO #path,
#filename
WHILE ##fetch_status <> -1
BEGIN
CREATE TABLE #Header
(
HeadString NVARCHAR(MAX)
)
DECLARE #Columns NVARCHAR(MAX) = ''
DECLARE #Query NVARCHAR(MAX) = ''
DECLARE #QUERY2 NVARCHAR(MAX) = ''
DECLARE #HeaderQuery NVARCHAR(MAX) = ''
SELECT #HeaderQuery = #HeaderQuery + 'bulk insert #Header from ''' + #path + #filename + '''
with(firstrow=1,lastrow=1)'
EXEC (#HeaderQuery)
SELECT #Columns = (SELECT QUOTENAME(value) + ' nvarchar(max)' + ','
FROM #Header
CROSS APPLY STRING_SPLIT(HeadString,',') FOR xml PATH(''))
IF ISNULL(#Columns,'') <> ''
BEGIN
SET #Columns = LEFT(#Columns,LEN(#Columns) - 1)
SELECT #Query = #Query + 'CREATE TABLE ' + Replace(#filename,'.csv','') + ' (' + replace(#Columns,'"','') + ')'
PRINT #Query
EXEC (#QUERY)
END
SELECT #QUERY2 = #QUERY2 + 'bulk insert ' + replace(Replace(#filename,'.csv',''),'.TPS','') + ' from ''' + #path + #filename + '''
with(firstrow=2,FORMAT=''csv'',FIELDTERMINATOR='','',ROWTERMINATOR=''\n'')'
EXEC (#QUERY2)
DROP TABLE #Header
FETCH NEXT FROM c1 INTO #path,
#filename
END
CLOSE c1
DEALLOCATE c1