2 回答
There are (at least) two options:
- Split the file into two separate files outside SQL Server, using your preferred scripting language; one with the header row and one with the details rows. Then use two
BULK INSERT
statements to load them into two different tables - Use SSIS and a Script Task to split the file into two data flows and process each one separately within the package
Personally I would use option 1, it's much easier. And there's no reason to load the data into a temp table, I would create a permanent table (or tables) just for loading this data. That is a lot easier to work with.
Thanks for the advice to Pondlife, i got the answer for my own question. Here we go;
Well as we know i have this text file that in the same time has the header and the detail
HR|001580/06|RG|11/01/2013 12:00|BG|3573|001580| IT|001580/01|1|00147066||1200|852.3|830.3|1.35|UNIDAD|0|31/12/2014 00:00 IT|001580/02|1|00147066||200|852.3|830.3|1.35|UNIDAD|1|31/12/2014 00:00 IT|001580/03|1|00147066||100|852.3|830.3|1.35|UNIDAD|55|31/12/2014 00:00 IT|001580/04|2|00254276||200|852.3|830.3|1.35|UNIDAD|0|31/12/2014 00:00 IT|001580/05|3|00305359||1700|852.3|830.3|1.35|UNIDAD|0|31/12/2014 00:00 IT|001580/06|3|00305359||300|852.3|830.3|1.35|UNIDAD|1|31/12/2014 00:00
So i need to:
- Read the file
- Insert the header into table1
- Insert the detail into table2
For the First Step i create a table and then i use the Sql BulkInsert
CREATE TABLE #ImportData
(
Field VARCHAR(max)
)
-- Insert the data into the first table
BULK INSERT #ImportData
FROM 'PATH FILE'
WITH
(
ROWTERMINATOR = '\n'
)
i got something like this.
We see that the rows it has delimiters( | ), that means the fields of the each table (HR - Header, IT - Details)
Then for my second and third step i need insert the rows on each table, but also i need to separate each fields of each row, so i create a procedure that receive a string and delimiter and return a table with each field of my string, i created the fields dynamically.
If you want to create the procedure you need to run this first
SET QUOTED_IDENTIFIER OFF
Then you can create it.
--EXEC spSplit
-- @InputString = 'IT|001580/01|1|00147066||1200|852.3|830.3|1.35|QUANTITY|0|31/12/2014 00:00', -- VARCHAR(max)
-- @Delimiter = '|' -- VARCHAR(50)
--SET QUOTED_IDENTIFIER OFF
ALTER PROCEDURE spSplit
-- =============================================
-- Author: Gabriel Jiménez
-- Create date: 2013-01-16
-- Description: Procedimiento creado para retornar
-- valores de cada campo de una cadena delimitada
-- =============================================
@InputString NVARCHAR(max),
@Delimiter VARCHAR(50)
AS
BEGIN
SET QUOTED_IDENTIFIER OFF
CREATE TABLE #Items (Field1 VARCHAR(max))
DECLARE @Item VARCHAR(max)
DECLARE @ItemList VARCHAR(max)
DECLARE @DelimIndex INT
DECLARE @PositionField INT
DECLARE @SqlTable VARCHAR(max)
DECLARE @SqlUpdate VARCHAR(max)
SET @ItemList = @InputString
SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
SET @PositionField = 0
WHILE (@DelimIndex != 0)
BEGIN
SET @SqlTable = "ALTER TABLE #Items ADD Field"
SET @SqlUpdate = "UPDATE #Items SET Field"
-- Set positions Rows and Fields
SET @PositionField = @PositionField + 1
SET @Item = SUBSTRING(@ItemList, 0, @DelimIndex)
IF @PositionField = 1
BEGIN
-- Insert the first data into the first field created on the table
INSERT INTO #Items (Field1) VALUES ( @Item )
END
ELSE
BEGIN
-- Create a dynamic table for the @InputString
SET @SqlTable = @SqlTable + CONVERT(VARCHAR, @PositionField)+ " VARCHAR(MAX)"
EXEC(@SqlTable)
SET @SqlUpdate = @SqlUpdate +
CONVERT(VARCHAR, @PositionField) + " = '" +
CONVERT(VARCHAR, @Item) +"'"
EXEC(@SqlUpdate)
END
-- Set @ItemList = @ItemList minus one less item
SET @ItemList = SUBSTRING(@ItemList, @DelimIndex+1, LEN(@ItemList)-@DelimIndex)
SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
END -- End WHILE
IF @Item IS NOT NULL -- At least one delimiter was encountered in @InputString
BEGIN
SET @SqlTable = "ALTER TABLE #Items ADD Field"
SET @SqlUpdate = "UPDATE #Items SET Field"
SET @SqlTable = @SqlTable + CONVERT(VARCHAR, @PositionField+1)+ " VARCHAR(MAX)"
EXEC(@SqlTable)
SET @SqlUpdate = @SqlUpdate +
CONVERT(VARCHAR, @PositionField+1) + " = '" +
CONVERT(VARCHAR, @ItemList) +"'"
EXEC(@SqlUpdate)
END
-- No delimiters were encountered in @InputString, so just return @InputString
ELSE
BEGIN
SET @SqlTable = "ALTER TABLE #Items ADD Field"
SET @SqlUpdate = "UPDATE #Items SET Field"
SET @SqlTable = @SqlTable + CONVERT(VARCHAR, @PositionField+1)+ " VARCHAR(MAX)"
EXEC(@SqlTable)
SET @SqlUpdate = @SqlUpdate +
CONVERT(VARCHAR, @PositionField+1) + " = '" +
CONVERT(VARCHAR, @InputString) +"'"
EXEC(@SqlUpdate)
END
SELECT * FROM #Items
SET QUOTED_IDENTIFIER ON
END -- End Procedure
GO
If you see i comment the three first lines for execute the procedure and you can get something like this
Well we not finish yet, we read the file, and we create the procedure that return the fields and now we need insert into each table, for that i create two temp table with static fields 'cause i know the fields of each table and then create Cursor for read each row on my #ImporData table.
CREATE TABLE #Header
(
Field1 VARCHAR(max),
Field2 VARCHAR(max),
Field3 VARCHAR(max),
Field4 VARCHAR(max),
Field5 VARCHAR(max),
Field6 VARCHAR(max),
Field7 VARCHAR(max),
Field8 VARCHAR(max)
)
-- Detail table is for the detail items
CREATE TABLE #Detail
(
Field1 VARCHAR(max),
Field2 VARCHAR(max),
Field3 VARCHAR(max),
Field4 VARCHAR(max),
Field5 VARCHAR(max),
Field6 VARCHAR(max),
Field7 VARCHAR(max),
Field8 VARCHAR(max),
Field9 VARCHAR(max),
Field10 VARCHAR(max),
Field11 VARCHAR(max),
Field12 VARCHAR(max)
)
DECLARE @Field NVARCHAR(max)
DECLARE Header CURSOR
FOR SELECT Field
FROM #ImportData
WHERE SUBSTRING(Field,1,2) = 'HR'
OPEN Header
FETCH NEXT FROM Header INTO @Field
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO #Header
EXEC spSplit @Field, '|'
FETCH NEXT FROM Header INTO @Field
END
CLOSE Header
DEALLOCATE Header
--Detail
--DECLARE @f NVARCHAR(max)
DECLARE Detail CURSOR
FOR SELECT Field
FROM #ImportData
WHERE SUBSTRING(Field,1,2) = 'IT'
OPEN Detail
FETCH NEXT FROM Detail INTO @Field
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO #Detail
EXEC spSplit @Field, '|'
FETCH NEXT FROM Detail INTO @Field
END
CLOSE Detail
DEALLOCATE Detail
--SELECT * FROM #ImportData
SELECT * FROM #Header
SELECT * FROM #Detail
DROP TABLE #ImportData
DROP TABLE #Header
DROP TABLE #Detail
After that if you put all the pieces on the same query you got this.
As i need to.
Again thanks Pondlife to give me the advice for the split.