Использование BULK INSERT для сопоставления столбцов - PullRequest
2 голосов
/ 11 ноября 2011

У меня есть CSV-файл с 6 миллионами строк. Каждая строка состоит из одного и того же формата, например, /

I,h,q,q,3,A,5,Q,3,[,5,Q,8,c,3,N,3,E,4,F,4,g,4,I,V,9000,0000001-100,G9999999990001800000000000001,G9999999990000001100PDNELKKMMCNELRQNWJ010, , , , , , ,D,Z

У меня есть 2 столбца в таблице.

Первый столбец должен быть полем 27 в CSV, а второй столбец должен быть целой строкой в ​​файле CSV.

Я попытался настроить файл формата, но не могу заставить его работать.

Можно ли вообще сделать такое отображение?

Вот что у меня есть:

BULK INSERT Staging FROM 'C:\Data.txt' 
   WITH 
   (
      FIELDTERMINATOR =',',
      ROWTERMINATOR ='\n',
      KEEPNULLS,
      formatfile='C:\format.fmt'
   )

Это мой формат файла

9.0
2
1       SQLCHAR       0       40     ","     27     Col27               SQL_Latin1_General_CP1_CI_AS
2       SQLCHAR       0       200     "\r\n"  1     Col1               SQL_Latin1_General_CP1_CI_AS

Для сравнения, у меня есть эта работа в SQLite, которая занимает 2 минуты 35 секунд.

1 Ответ

4 голосов
/ 11 ноября 2011

Вы можете взломать этот гайку несколькими способами, но я сделал так, чтобы массово вставить CSV-файл WHOLE в временную таблицу с помощью динамического SQL:

CREATE TABLE #BulkLoadData(
    RecordData NVARCHAR(max)
)


SET @SQL = 'BULK INSERT #BulkLoadData FROM ''' + @SourceFileFullPath + ''' '
SET @SQL = @SQL + 'WITH (FORMATFILE = ''' + @UPXInputFileBulkLoadFormat + 'UPXInputFileBulkLoadFormat.xml'', TABLOCK, ROWS_PER_BATCH = 2500 ) '

EXECUTE (@SQL)

Затем вы можете вставить данные вцелевая таблица выглядит следующим образом:

INSERT INTO dbo.TargetTable
SELECT dbo.fnParseString(27, ',', RecordData), RecordData

Вам нужно создать функцию разбора примерно так:

CREATE FUNCTION [dbo].[fnParseString]
(
    @Section SMALLINT,
    @Delimiter CHAR,
    @Text VARCHAR(MAX)
)
RETURNS VARCHAR(8000)
AS

BEGIN
DECLARE @startindex NUMERIC(18,0),
     @length NUMERIC(18,0),
     @FieldPosition INT

 SET @FieldPosition = ABS(@Section) - 1
 SET @startindex = 0


 WHILE @FieldPosition != 0
 BEGIN
    SET @FieldPosition = @FieldPosition - 1
     SET @startindex = CHARINDEX(@Delimiter, @Text, @startindex + 1) 
 END     


 SET @Text = SUBSTRING(@Text, @startindex + 1, LEN(@Text) - @startindex)
 SET @Text = SUBSTRING(@Text, 0, CHARINDEX(@Delimiter, @Text))

 RETURN @Text
END

Надеюсь, это поможет!Если вам нужна помощь с файлом формата, дайте мне знать.

Вот содержимое файла формата:

<?xml version="1.0"?>
<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <RECORD>
    <FIELD ID="1" xsi:type="CharTerm" TERMINATOR="\n" MAX_LENGTH="8000" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
  </RECORD>
  <ROW>
    <COLUMN SOURCE="1" NAME="RecordData" xsi:type="SQLVARYCHAR"/>
  </ROW>
</BCPFORMAT>
...