0
4

2 回答 2

0

There are (at least) two options:

  1. 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
  2. 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.

于 2013-01-16T18:17:15.847 回答
0

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:

  1. Read the file
  2. Insert the header into table1
  3. 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.

于 2013-01-17T17:10:31.040 回答