web-dev-qa-db-fra.com

L'insertion en bloc SQL avec le paramètre FIRSTROW ignore la ligne suivante

Je n'arrive pas à comprendre comment cela se passe.

Voici un exemple de fichier que j'essaie d'insérer en bloc dans SQL Server 2005:

***A Nice HEADER HERE***
0000001234|SSNV|00013893-03JUN09
0000005678|ABCD|00013893-03JUN09
0000009112|0000|00013893-03JUN09
0000009112|0000|00013893-03JUN09

Voici ma déclaration d'insertion en vrac:

BULK INSERT sometable
FROM 'E:\filefromabove.txt
WITH
(
FIRSTROW = 2,
FIELDTERMINATOR= '|',
ROWTERMINATOR = '\n'
)

Mais, pour une raison quelconque, le seul résultat que je puisse obtenir est le suivant:

0000005678|ABCD|00013893-03JUN09
0000009112|0000|00013893-03JUN09
0000009112|0000|00013893-03JUN09

Le premier enregistrement est toujours ignoré, sauf si j'enlève complètement l'en-tête et n'utilise pas le paramètre FIRSTROW. Comment est-ce possible?

Merci d'avance!

8
gibbo

Je ne pense pas que vous puissiez sauter des lignes dans un format différent avec BULK INSERT/BCP.

Quand je lance ceci:

TRUNCATE TABLE so1029384

BULK INSERT so1029384
FROM 'C:\Data\test\so1029384.txt'
WITH
(
--FIRSTROW = 2,
FIELDTERMINATOR= '|',
ROWTERMINATOR = '\n'
)

SELECT * FROM so1029384

Je reçois:

col1                                               col2                                               col3
-------------------------------------------------- -------------------------------------------------- --------------------------------------------------
***A Nice HEADER HERE***
0000001234               SSNV                                               00013893-03JUN09
0000005678                                         ABCD                                               00013893-03JUN09
0000009112                                         0000                                               00013893-03JUN09
0000009112                                         0000                                               00013893-03JUN09

Il semble que cela nécessite le '|' même dans les données d'en-tête, car elles sont lues jusqu'à la première colonne - engloutissant une nouvelle ligne dans la première colonne. Évidemment, si vous incluez un paramètre de terminaison de champ, il s'attend à ce que chaque ligneDOITen avoir un.

Vous pouvez supprimer la ligne avec une étape de pré-traitement. Une autre possibilité consiste à sélectionner uniquement des lignes complètes, puis à les traiter (en excluant l'en-tête). Ou utilisez un outil capable de gérer cela, comme SSIS.

14
Cade Roux

Peut-être vérifier que l'en-tête a la même fin de ligne que les lignes de données réelles (comme spécifié dans ROWTERMINATOR)?

Mise à jour: à partir de MSDN :

L'attribut FIRSTROW n'est pas destiné à ignorer les en-têtes de colonne. Ignorer les en-têtes n'est pas pris en charge par l'instruction BULK INSERT. Lorsque vous ignorez des lignes, le moteur de base de données SQL Server examine uniquement les terminateurs de champ et ne valide pas les données dans les champs des lignes ignorées.

8
Marc Gravell

J'ai trouvé plus facile de simplement lire la ligne entière dans une colonne, puis d'analyser les données à l'aide de XML.

IF (OBJECT_ID('tempdb..#data') IS NOT NULL) DROP TABLE #data
CREATE TABLE #data (data VARCHAR(MAX))

BULK INSERT #data FROM 'E:\filefromabove.txt' WITH (FIRSTROW = 2, ROWTERMINATOR = '\n')

IF (OBJECT_ID('tempdb..#dataXml') IS NOT NULL) DROP TABLE #dataXml
CREATE TABLE #dataXml (ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED, data XML)

INSERT #dataXml (data)
SELECT CAST('<r><d>' + REPLACE(data, '|', '</d><d>') + '</d></r>' AS XML)
FROM #data

SELECT  d.data.value('(/r//d)[1]', 'varchar(max)') AS col1,
        d.data.value('(/r//d)[2]', 'varchar(max)') AS col2,
        d.data.value('(/r//d)[3]', 'varchar(max)') AS col3
FROM #dataXml d
6
norlando

Vous pouvez utiliser l'extrait ci-dessous

BULK INSERT TextData
FROM 'E:\filefromabove.txt'
WITH
(
FIRSTROW = 2,
FIELDTERMINATOR = '|',  --CSV field delimiter
ROWTERMINATOR = '\n',   --Use to shift the control to next row
ERRORFILE = 'E:\ErrorRows.csv',
TABLOCK
)
0
suresh kumar