Click here to Skip to main content
15,890,438 members
Articles / Programming Languages / SQL

Import Data from a Text or CSV file into SQL Server

Rate me:
Please Sign up or sign in to vote.
5.00/5 (6 votes)
26 Nov 2011CPOL2 min read 437.4K   18   6
Import Data from a Text or CSV file into SQL Server

I was recently in need of importing data from a CSV (Comma Separated File) to a table in SQL Server 2008.
After searching in Google for a little while, I found this blog entry from Pinal Dave (SQL Authority) which always provides good content.

Besides passing along the technique described in Pinal's blog post, I would like to expand by explaining a few snags that I ran into.

My source data in the CSV file looks something like this:

HOU009,Windows Phone 7,Will Martinez,
11/10/2011,Houston; TX,999,2
HOU010,WPF for Business Applications,Will Martinez,
11/15/2011,Houston; TX,695,1

More or less, I have all the data needed to fill the columns of my target table. My assumption is that my column id of type uniqueidentifier is going to be auto-generated. This is my table:

SQL
CREATE TABLE [dbo].[Courses](
   [id] [uniqueidentifier] NOT NULL DEFAULT NEWSEQUENTIALID(),
   [code] [varchar](50) NOT NULL,
   [description] [varchar](200) NULL,
   [instructor] [varchar](50) NULL,
   [date] [date] NULL,
       [venue] [varchar](50) NULL,
   [price] [money] NULL,
       [duration] [int] NULL,
 CONSTRAINT [PK_Courses] 
    PRIMARY KEY CLUSTERED ([id] ASC,[code] ASC )
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, _
	IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) 
  ON [PRIMARY]) ON [PRIMARY]

As you may notice, I have two datatypes that may be challenging, first my primary key is of type uniqueidentifier and also, I'm using a date datatype.

Initially, I tried to import my data from the CSV file using the below statement:

SQL
bulk insert [dbo].[Courses]
from 'C:\Courses.csv'
with (fieldterminator = ',', rowterminator = '\n')
go

On my first try, I did not have any luck. I ran into the below issue:

Msg 4861, Level 16, State 1, Line 1
Cannot bulk load because the file "C:\Courses.csv" 
could not be opened. Operating system error code 5
(Access is denied.).

Moved my file to the Public directory and then made sure permissions were set to 'Everyone'. No luck, although I did not get the "access denied" error. My insert returns 0 row(s) affected.

At this point, my guess was that I had a couple of issues:

  • First, I did not have a value for the Id column which is our primary key
  • My column of type date could be a problem if there is an implicit conversion of string data

To work around the problem, I decided to create a new temporary table, without a primary key and with a datetime datafield. Here is the table:

SQL
CREATE TABLE [dbo].[CoursesTemp](
   [code] [varchar](50) NOT NULL,
   [description] [varchar](200) NULL,
   [instructor] [varchar](50) NULL,
   [date] [datetime] NULL,
   [venue] [varchar](50) NULL,
   [price] [money] NULL,
   [duration] [int] NULL)

Ran my insert statement again:

SQL
bulk insert [dbo].[CoursesTemp]
from 'C:\Users\Public\Downloads\Courses.csv'
with (fieldterminator = ',', rowterminator = '\n')
go

Success! Finally got to see what I was waiting for...(20 row(s) affected).

At this point, life is easy. I can use the data I just inserted in the temporary table and use it to insert into the "live" table.

SQL
insert [dbo].[Courses]
  (code, description, instructor, date, venue, duration)
select 
   code, description, instructor, cast(date as date), venue,
   duration
from [dbo].[CoursesTemp]

Notice that my Id column is not listed since it has a uniqueidentifier with a default of NEWSEQUENTIALID , it automatically generates a GUID for each record.

To deal with the issue of the date field, I noticed that there is a CAST statement that will convert the data to the appropriate datatype.

Below is how the data looks like in my table:

?

Now, I have the data I needed and my id column has nice GUIDs generated for every record.
I'm ready to get some work done.

Hope this helps somebody out there,
Will

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionIs there another way to do this, but without Bulk Insert? Pin
Boris Krepkanovich14-Feb-15 23:07
Boris Krepkanovich14-Feb-15 23:07 
QuestionCSV not supported by SQL Server Bulk import Pin
nanonerd18-Sep-13 10:34
nanonerd18-Sep-13 10:34 
QuestionQuestion about import txt file.. please help Pin
GaboBigale16-Jan-13 5:35
GaboBigale16-Jan-13 5:35 
AnswerRe: Question about import txt file.. please help Pin
gmtzgtz16-Jan-13 6:46
gmtzgtz16-Jan-13 6:46 
Hi,
Here is what I would suggest, for starters, I think you are inserting all your row data in a single column on #temp, what I would suggest is to create a hard table, with the appropriate structure, for example:

CREATE TABLE ImportData
(Campo1 varchar(200),
Campo2 varchar(200),
Campo3 varchar(200),
Campo4 varchar(200), etc. You should end up with 11 columns...)


I would make all the columns a string for simplicity.

Then you do your bulk insert in to the new table, provided you indicated the right number of columns, and the separator indicator is correct, you should have now is all the data in separate columns.

Not sure if this is a problem or not, but on the example you wrote, seems like you have a line with a header and detailed mixed, (the first line) because I see a, HR and IT rows in one line, this would be a problem; the source file would have to be modified to only have an HR or IT row per line.

Just FYI this is what I would to next:

I would create two separate tables, one for the header and one for the details, You probably want to start the table adding an Id column and define it as an identity key which will make each row unique, then you will insert the header first by doing:

INSERT INTO HeaderTableName ( [Your 7 Column List]...)
SELECT [Your Seven Column List from ImportData]
WHERE RTRIM(Campo1) = 'HR'


You won't include the Id column since that will be auto-populated by SQL Server.
This will separate all the header records. I'm suggesting you to use an ID but somehow you will need to have a column that will allow you to join the header and the detail, I think you already have field that does that, it seems that's your second field, what appears to be an order number, '001580' the problem is that you have other info in there (/60). So I would use the Id for easier joins in the future.

Once you have the header table, you need to insert into the Detail Table, again you will need to create a table with your 11 detail columns, and I would add two additional columns an Id which is an identity key which will make each row unique and another integer column which is a reference to your header. This will allow you to easily join the records of the two tables in the future.

To populate the table you do another INSERT SELECT with a JOIN

SQL
INSERT INTO DetailTableName ( HeaderId, [then your 11 detail columns] )
SELECT a.Id, [Your 11 Detail Columns from ImportData]...
FROM HeaderTableName a JOIN ImportData b ON ( Substring( Maybe the second field that refers to 001580 on HeaderTableName) = Subtring(again your second field in ImportData that contains 001580) )
WHERE RTRIM(b.Campo1) = 'IT'


Apologies, If I was trying to be too basic with my explanation, you may already know all about Ids and keys.

Hope this helps you somehow. Suerte.
Will
GeneralRe: Question about import txt file.. please help Pin
GaboBigale17-Jan-13 6:22
GaboBigale17-Jan-13 6:22 
General:) Pin
Hector Perales26-Apr-12 20:05
Hector Perales26-Apr-12 20:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.