How do I BULK INSERT with additional column showing filename? - sql-server

I'm still getting used to SQL, so before I get to using stored procedure, I would like to understand how to use BULK INSERT effectively first.
I need to combine 50+ csv files and dump them into an SQL table. The problem is, I'd like to be able to tell each record apart (as in, each record belongs to a certain csv file, which I will identify by the file name).
Here's a small example of what I want:
CREATE TABLE ResultsDump
(
PC FLOAT,
Amp VARCHAR(50),
RCS VARCHAR(50),
CW VARCHAR(50),
State0 VARCHAR(50),
State1 VARCHAR(50),
)
BULK INSERT ResultsDump
FROM 'c:\distance1000_7_13_2010_1_13PM_Avery DennisonAD_2300008_10S_Lock.csv'
WITH
(
FIRSTROW = 2,
MAXERRORS = 0,
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
)
BULK INSERT ResultsDump
FROM 'c:\distance1000_7_13_2010_2_27PM_Avery DennisonAD_2300009_10S_Lock.csv'
WITH
(
FIRSTROW = 2,
MAXERRORS = 0,
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
)
BULK INSERT ResultsDump
FROM 'C:\distance1000_7_13_2010_2_58PM_Avery DennisonAD_230000A_10S_Lock.csv'
WITH
(
FIRSTROW = 2,
MAXERRORS = 0,
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
)
BULK INSERT ResultsDump
FROM 'c:\distance1000_7_13_2010_3_21PM_Avery DennisonAD_230000B_10S_Lock.csv'
WITH
(
FIRSTROW = 2,
MAXERRORS = 0,
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
)
BULK INSERT ResultsDump
FROM 'c:\distance1000_7_13_2010_3_41PM_Avery DennisonAD_230000C_10S_Lock.csv'
WITH
(
FIRSTROW = 2,
MAXERRORS = 0,
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
)
I know this is an inefficient way of doing things, but I definitely like to figure out how to manually dump one file in the SQL table in the format I want before I start to create a stored procedure.
In the new table, I want something like this:
FileName,PC,Amp,RCS,CW,State0,State1
c:\distance1000_7_13_2010_1_13PM_Avery DennisonAD_2300008_10S_Lock.csv, ...
...
...
c:\distance1000_7_13_2010_2_27PM_Avery DennisonAD_2300009_10S_Lock.csv, ...
...
...
c:\distance1000_7_13_2010_2_58PM_Avery DennisonAD_230000A_10S_Lock.csv, ...
...
...
Any simple suggestions or referrals to specific functions would be great! Remember, I'm getting used to SQL and it'd be great if I could take this one step at a time, that's why I'm starting with such a simple question.
Thanks in advance!

You can add a column FileName varchar(max) to the ResultsDump table, create a view of the table with the new column, bulk insert into the view, and after every insert, set the filename for columns where it still has its default value null:
CREATE TABLE dbo.ResultsDump
(
PC FLOAT,
Amp VARCHAR(50),
RCS VARCHAR(50),
CW VARCHAR(50),
State0 VARCHAR(50),
State1 VARCHAR(50),
)
GO
ALTER TABLE dbo.ResultsDump ADD [FileName] VARCHAR(300) NULL
GO
CREATE VIEW dbo.vw_ResultsDump AS
SELECT
PC,
Amp,
RCS,
CW,
State0,
State1
FROM
ResultsDump
GO
BULK INSERT vw_ResultsDump
FROM 'c:\distance1000_7_13_2010_1_13PM_Avery DennisonAD_2300008_10S_Lock.csv'
WITH
(
FIRSTROW = 2,
MAXERRORS = 0,
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
)
UPDATE dbo.ResultsDump
SET [FileName] = 'c:\distance1000_7_13_2010_1_13PM_Avery DennisonAD_2300008_10S_Lock.csv'
WHERE [FileName] IS NULL
BULK INSERT vw_ResultsDump
FROM 'c:\distance1000_7_13_2010_2_27PM_Avery DennisonAD_2300009_10S_Lock.csv'
WITH
(
FIRSTROW = 2,
MAXERRORS = 0,
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
)
UPDATE dbo.ResultsDump
SET [FileName] = 'distance1000_7_13_2010_2_27PM_Avery DennisonAD_2300009_10S_Lock.csv'
WHERE [FileName] IS NULL

Try this,
ALTER PROCEDURE [dbo].[ReadandUpdateFileNames_SP]
(
#spRequestId NVARCHAR(50)
,#LoopCounter INT =0
,#MaxFIVId INT=0
,#spFileName NVARCHAR(100)=NULL)
AS
BEGIN
SET NOCOUNT ON
BEGIN TRY
BEGIN TRAN
-- To read filename's from the Request Id and store it in a temp table
DECLARE #cmd nvarchar(500)
SET #cmd = 'dir D:\Input\REQUEST-'+#spRequestId+' /b '
--PRINT #cmd
DECLARE #DirOutput TABLE(
ID INT IDENTITY
, files varchar(500))
INSERT INTO #DirOutput
EXEC master.dbo.xp_cmdshell #cmd
SELECT * FROM #DirOutput WHERE files IS NOT NULL ORDER BY ID
----Read files by RequestId BEGIN
SELECT #LoopCounter = min(ID) , #MaxFIVId = max(ID)
FROM #DirOutput
WHILE(#LoopCounter IS NOT NULL AND #LoopCounter<#MaxFIVId)
BEGIN
-- Create temp table to store FIVItems
CREATE TABLE Items_TEMP
(
ControlID NVARCHAR(50)
, UNRS_Code NUMERIC(18,0)
, UNRS_Code_S NUMERIC(18,0)
, Ordered_Quantity NUMERIC(18,3)
, Sent_Quantity NUMERIC(18,3)
, Accepted_Quantity NUMERIC(18,3)
, Unit_Food_Price NUMERIC(18,2)
, Total_Price NUMERIC(18,2)
)
SELECT #spFileName=files FROM #DirOutput WHERE ID=#LoopCounter
PRINT #LoopCounter
DECLARE #spControlId NVARCHAR(50)
SET #spControlId='FFO'+ Substring(#spFileName, 4, (len(#spFileName)-7))
--PRINT #spControlId
DECLARE #sqlCmd NVARCHAR(MAX)
SET #sqlCmd='BULK INSERT
Items_TEMP
FROM ''D:\Input\REQUEST-'+#spRequestId+'\'+#spFileName+'''
WITH(
FIELDTERMINATOR='',''
, ROWTERMINATOR=''\n''
)'
PRINT #sqlCmd
EXECUTE sp_executesql #sqlCmd
---Add a new column to the table which is not present in the CSV
ALTER TABLE Items_TEMP ADD OrderId NUMERIC(18,0)NULL
UPDATE Items_TEMP SET ControlID=#spControlId,OrderId=(SELECT OrderId FROM dbo.Orders WHERE ControlID=#spControlId)
SELECT * FROM Items_TEMP
--DROP FIVItems_TEMP table once CSV output generated
DROP TABLE Items_TEMP
SET #LoopCounter=#LoopCounter+1
END
----****END***
COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN
PRINT 'ROLLBACK'
PRINT Error_Message()
SELECT ERROR_LINE() AS ErrorLine;
END CATCH
SET NOCOUNT OFF
END

Related

How to insert data from multiple CSV files into one single table in SQL?

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.

How to Pass Parameter as a List In a Stored procedure in a dynamic Insert Query

I have a scenario that #PRIVILEGEID will have multiple value and #ROLEID will be same every time for those privilege Id.
So I have to insert the data into table.
Below is the Code For Procedure:-
ALTER PROCEDURE [dbo].[ADD_ROLE] (
#ROLENAME varchar(50),
#PRIVILEGEID int )
AS
BEGIN
DECLARE #QUERY varchar(1000);
DECLARE #ROLEID int;
SET #ROLEID = ( SELECT Max(ROLEID)
FROM ( SELECT
Max(CREATED_DATE) AS MAX_DATE,
ROLEID
FROM ROLE
WHERE ROLENAME = #ROLENAME
--(ROlename can be changed dynamically, take 'Manager' as example as of now.)
AND CREATED_DATE IS NOT NULL
GROUP BY ROLEID ) X );
--PRINT #ROLEID
SET #QUERY = 'INSERT INTO [ROLES_PRIVILEGES] (ROLEID,PRIVILEGEID) VALUES (''' + Cast(#ROLEID AS varchar) + ''',''' + Cast(#PRIVILEGEID AS varchar) + ''')';
EXECUTE ( #QUERY );
END;
Now #PRIVILEGEID will have a dynamic list of multiple values for the fixed #ROLEID and My issue is I can pass only one #PRIVILEGEID at one time.
Exec ADD_ROLE 'BACKOFFICE',#PRIVILEGEID #PRIVILEGEID=[2, 3, 4, 5, 6]
-- (How to pass multiple value for PRIVILEGEID )
I have tried While loop also but not sure how to implement it.
Please help.
Here is an example where I take a comma delimited string and dump into a table. This process works by converting it into xml and using xmlqry to parse. I like it because I feel its easier to read and looks less convoluted.
Let me know if it works for you.
USE yourDatabase
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[_parsedelimited]
(
#str varchar(max)
)
AS
BEGIN
if object_id('tempdb..#Emails') is not null drop table #Emails;
CREATE TABLE #Emails (Email varchar(2500));
Declare #x XML;
select #x = cast('<A>'+ replace(#str,',','</A><A>')+ '</A>' as xml);
INSERT INTO #Emails (Email)
select
t.value('.', 'varchar(50)') as inVal
from #x.nodes('/A') as x(t);
SELECT * FROM #Emails;
drop table #Emails;
END
GO
Consider the following:
declare #role varchar(20) = 'BACKOFFICE',
#PRIVILEGEID varchar(100) = '2,3,4,5,6';
select #role, *
from string_split(#PRIVILEGEID, ',');
Using that select, you should be able to insert it into whatever table you'd like.

BULK Insert Fails with different files sizes

I have this problem where bulk insert fails with different files sizes, specifically, the first file would contain 433 rows while the second file has 2 rows only. But when I insert the 2 rowed file by itself, there's no error.
I have this as my bulk insert statement
set #sql = 'BULK INSERT #temptable
FROM '''+#location+'''
WITH
(
FIELDTERMINATOR = '','',
ROWTERMINATOR = ''\n'',
MAXERRORS = 100,
TABLOCK,
FIRSTROW = 2
)'
The above statement is contained in a stored procedure.
For more information, I will put my stored procedure here.
USE [THERMOWAVE]
GO
/****** Object: StoredProcedure [dbo].[UploadOmronData] Script Date: 02/13/2017 13:48:54 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[UploadOmronData]
#location as nvarchar(max)
as
begin
declare #sql as nvarchar(max)
-- give #location data from VB.net
--declare #location as varchar(max)
--set #location = 'C:\Users\jsumgo\Documents\Visual Studio 2010\Projects\TestUploader\TestUploader\bin\Debug\12320161428420dataUpload.csv'
-- Joshua Magsino 11/28/2016
-- TSql to upload dynamic column data source
--before uploading, make sure that datasource table columns are named equal to database table column
--Check if data is to be stored as reference or could be destroyed
--Check database to store and columns that would be affected
--set configurations to enable Ad Hoc Distributed Queries
/*
sp_configure 'show advanced options', 1;
RECONFIGURE;
GO
sp_configure 'Ad Hoc Distributed Queries', 1;
RECONFIGURE;
GO
*/
-- configure SQL to execute Ad Hoc Queries using MSOFFICE 2010
/*
USE [master]
GO
EXEC master.dbo.sp_MSset_oledb_prop N'Microsoft.ACE.OLEDB.12.0', N'AllowInProcess', 1
GO
EXEC master.dbo.sp_MSset_oledb_prop N'Microsoft.ACE.OLEDB.12.0', N'DynamicParameters', 1
GO
*/
-- fill temptable with data
---------------------------------------------------------------------------------------------------------------
--drop table #temptable
--create blank temptable
create table #temptable
(
[Number] Varchar(20)
)
--declare #sql as varchar(max)
declare #cursor CURSOR
declare #colname as nvarchar(30)
SET #cursor = CURSOR FOR
(Select colname from dbo.sorting)
OPEN #cursor
FETCH NEXT
FROM #cursor INTO #colname
WHILE ##FETCH_STATUS = 0
BEGIN
-- add from column 2 to end
if #colname <> 'Number'
begin
set #sql = 'ALTER TABLE #temptable ADD ['+#colName+'] NVARCHAR(max) NULL'
EXEC sp_executesql #sql, N'#colname nvarchar(max)', #colname
end
FETCH NEXT
FROM #cursor INTO #colName
END
CLOSE #cursor
DEALLOCATE #cursor
---------------------------------------------------------------------------------------------------------------
--declare #location as varchar(max)
--set #location = 'D:\Omron Data\Data\sample\asdasdasdasdasd - Copy.csv'
--declare #sql as varchar(max)
--Insert Data from CSV file to Temptable
set #sql = 'BULK INSERT #temptable
FROM '''+#location+'''
WITH
(
FIELDTERMINATOR = '','',
ROWTERMINATOR = ''\n'',
MAXERRORS = 100,
TABLOCK,
FIRSTROW = 2
)'
EXEC sp_executesql #sql, N'#location as nvarchar(max)', #location
--Insert Statement
--If the location of the new column is in the last column of the CSV file, then direct bulk insert
--safe solution is to insert based on the column name of each table
--cursor is needed
DECLARE #DBcursor CURSOR
DECLARE #DBColname as varchar(30)
DECLARE #DBCOL as nvarchar(max)
--Get Table Names from dbo.sorting
--since all table names are inserted from dbo.sorting, get column names from dbo.sorting
SET #DBcursor = CURSOR FOR
(Select colname from dbo.sorting)
OPEN #DBcursor
FETCH NEXT
FROM #DBcursor INTO #DBColname
WHILE ##FETCH_STATUS = 0
BEGIN
--assemble columns
set #DBCOL = (isnull(#DBCOL,''))+'['+ #DBColname +'],'
FETCH NEXT
FROM #DBcursor INTO #DBColname
END
CLOSE #DBcursor
DEALLOCATE #DBcursor
--remove last (,) from columns
set #DBCOL =LEFT(#DBCOL, LEN(#DBCOL) - 1)
--insert data from temptable to DataUpload
set #sql = 'insert into DataToUpload ('+#DBCOL+') select '+#DBCOL+' from #tempTable'
EXEC sp_executesql #sql,N'#DBCOL NVARCHAR(max)', #DBCOL
--Put BatchID for DataUpload
--BatchId format,Batch + Number(000) + year + month + day
declare #number as nvarchar(max)
set #number = RIGHT('000' +CAST((select ISNULL(max(case when BatchID = null or BatchID = '' then '000' else right(SUBSTRING(BatchID,1,8),3)+ 1 end),'000') from DataToUpload)AS VARCHAR(3)),3)
set #sql = 'update DataToUpload set BatchID = ''Batch'+cast(#number as varchar(max))+cast(year(getdate()) as varchar(4))+''+cast(MONTH(getdate())as varchar(2))+''+cast(DAY(getdate())as varchar(2)) +''' where BatchID is null'
EXEC sp_executesql #sql,N'#number NVARCHAR(max)', #number
--select * from DataToUpload order by BAtchID,Number asc
--select * from dbo.Sorting
--select * from temptable
--delete from DataToUpload
--clear dbo.sorting
delete from dbo.Sorting
--remove temptable
drop table #temptable
DBCC FREEPROCCACHE WITH NO_INFOMSGS;
end
and then the command in a vb.net system that fires the stored procedure through here.
Sub UploadOmronData(ByVal location As String)
'SQL Stored Procedure -- Save data from CSV file to SQL
Dim sqlcom As New SqlClient.SqlCommand
Try
With sqlcom
conn.Open()
.Connection = conn
.CommandTimeout = 100
.CommandText = "dbo.UploadOmronData"
.CommandType = CommandType.StoredProcedure
.Parameters.AddWithValue("#location", location)
.ExecuteReader()
End With
Catch ex As Exception
MsgBox(ex.Message + " " + location)
GC.Collect()
sqlcom.Dispose()
frmMain.Close()
End Try
conn.Close()
sqlcom.Dispose()
GC.Collect()
End Sub
And the error message which I receive:
Bulk load data conversion error (truncation) for row 2, column 1 (Number).
Bulk load data conversion error (truncation) for row 3, column 1 (Number).
ADDED INFORMATION
Here is the table structure of dbo.DataToUpload
CREATE TABLE [dbo].[DataToUpload](
[Number] [int] NULL,
[Date&Time] [nvarchar](max) NULL,
[ms] [nvarchar](50) NULL,
[CH34] [nvarchar](50) NULL,
[CH35] [nvarchar](50) NULL,
[CH36] [nvarchar](50) NULL,
[CH37] [nvarchar](50) NULL,
[CH38] [nvarchar](50) NULL,
[CH39] [nvarchar](50) NULL,
[Alarm1-10] [nvarchar](50) NULL,
[Alarm11-20] [nvarchar](50) NULL,
[Alarm21-30] [nvarchar](50) NULL,
[Alarm31-40] [nvarchar](50) NULL,
[AlarmOut] [nvarchar](50) NULL,
[BatchID] [nvarchar](50) NULL,
[CH31] [nvarchar](20) NULL,
[CH32] [nvarchar](20) NULL,
[CH33] [nvarchar](20) NULL
) ON [PRIMARY]
and the rows that I'm trying to insert
Number,Date&Time,ms,CH34,CH35,CH36,CH37,CH38,CH39,Alarm1-10,Alarm11-20,Alarm21-30,Alarm31-40,AlarmOut
1,2016-08-08 16:23:16,000,+61.2,+64.0,+35.4,+94.4,+185.4,+151.2,LLLLLLLLLL,LLLLLLLLLL,LLLLLLLLLL,LLLLLLLLLL,LLLL
2,2016-08-08 16:23:26,000,+61.1,+64.4,+35.4,+94.3,+185.4,+151.2,LLLLLLLLLL,LLLLLLLLLL,LLLLLLLLLL,LLLLLLLLLL,LLLL
and If it mayhelp, the system I created is a background worker, since I have to run the code always.
I reckon the cause is that you're asking BULK INSERT to load 14 columns of data, but you're importing into #TempTable which doesn't have enough fields in it.
Your code creates a #tempTable table, and you use a CURSOR to add extra fields to it... but I reckon the end result isn't a table with 14 fields in it.
Before your BULK INSERT #temptable command gets run, how many fields are in the #temptable table ?
For example, if you just had one field in this table, when you ran the bulk-insert it would insist on trying to import the entire row into that one field, complete with all the commas, but, of course, it doesn't fit in a 20-character string.
CREATE TABLE #temptable
(
[Number] VARCHAR(20)
)
The solution... simply change your temporary table to have the correct number of columns, and the BULK INSERT will work fine:
CREATE TABLE #temptable
(
[Number] NVARCHAR(200),
[Datey] datetime,
[ms] NVARCHAR(200),
[CH34] NVARCHAR(200),
[CH35] NVARCHAR(200),
[CH36] NVARCHAR(200),
[CH37] NVARCHAR(200),
[CH38] NVARCHAR(200),
[CH39] NVARCHAR(200),
[Alarm110] NVARCHAR(200),
[Alarm1120] NVARCHAR(200),
[Alarm2130] NVARCHAR(200),
[Alarm3140] NVARCHAR(200),
[AlarmOut] NVARCHAR(200)
)
Good luck !
P.S. One piece of the puzzle which is missing.... What data do you have in your dbo.sorting table ? This will dictate which fields end up in your temporary table, but you don't explain how this table is populated, or what data it contains.
The attributes
[BatchID] [nvarchar](50) NULL,
[CH31] [nvarchar](20) NULL,
[CH32] [nvarchar](20) NULL,
[CH33] [nvarchar](20) NULL
are missing from your file. With BULK_INSERT the columns have to match perfectly. Fix the number of columns, and it should fix the error.

Insert filename during bulk load in SQL Server

DECLARE #SQL_BULK VARCHAR(MAX)
SET #SQL_BULK = 'BULK INSERT [dbo].[Table]
FROM ''' + #BatchFileName + '''
WITH
(
FIRSTROW = 2,
FIELDTERMINATOR = ''\t'',
ROWTERMINATOR = ''0x0a''
)'
EXEC (#SQL_BULK)
I have this code to do a bulk load. Works fine, but I would like to have the #BatchFileName also in there as a column (each row contains the same value).
Is this possible during the bulk load? Or how can I add it later on in a separate function?
Thanks in advance
i use this script to iterate and bulkinsert files in directory:
create table #x (name varchar(200))
DECLARE #query varchar (1000),#conta int ,#query2 varchar (1000),#NOME varchar(50)
set #conta=1
set #query ='master.dbo.xp_cmdshell "dir '+'C:\directoryname'+'*.csv' +' /b"'
insert #x exec (#query)
delete from #x where name is NULL
select identity(int,1,1) as ID, name into #y from #x
drop table #x
WHILE #conta<221 --number of files
BEGIN
SELECT #NOME=name FROM #y WHERE ID=#conta
set #Query2 ='BULK INSERT [dbo].[tablename] FROM '+ '''C:\directoryname'+#NOME+'''
WITH (
FIELDTERMINATOR = '','',ROWTERMINATOR = ''0x0a'')'
SELECT #query2
exec (#Query2)
set #conta=#conta+1
END
drop table #y

Bulk insert file path as stored procedure parameter

I'm trying to create a stored procedure to import from CSV. Everything works if I have a hard coded file path, but I want to take a file path as a parameter. When I try SQL Sever Management Studio generates an error:
Incorrect syntax near '#filePath'.
(In fact, if I put anything but a pure string(eg. 'C:'+'/dir') it gives an error.)
This is a simplified version of my code:
Create procedure [importFile](#filePath varchar(Max))
AS
BEGIN
create table #Temp
(
row1 int,
row2 varchar(5),
row3 bit
)
BULK insert
#Temp
from #filePath
With(
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
)
...
END
Any explanation?
Use dynamic SQL to inject the file name variable into a string with the bulk insert statement and the use sp_executesqlto execute it. You might want to add some error checking to check that the path is valid and so on.
CREATE PROCEDURE [importFile] (#filePath VARCHAR(MAX))
AS
BEGIN
CREATE TABLE #Temp
(
row1 int,
row2 varchar(5),
row3 bit
)
DECLARE #SQL NVARCHAR(MAX) = ''
SET #SQL = N'
BULK INSERT #Temp
FROM ''' + #filePath + '''
WITH (
FIELDTERMINATOR = '','',
ROWTERMINATOR = ''\n''
)'
-- ...
EXEC sp_executesql #SQL
END
-- to run it:
EXEC importFile 'd:\test.csv'

Resources