Question

J'exporte des données par programmation d'Excel vers SQL Server 2005 à l'aide de SqlBulkCopy. Cela fonctionne très bien, le seul problème que j'ai, c'est qu'il ne conserve pas la séquence de lignes que j'ai dans un fichier Excel. Je n'ai pas de colonne à classer, je veux juste que les enregistrements soient insérés dans le même ordre dans lequel ils apparaissent dans la feuille de calcul Excel.

Je ne peux pas modifier le fichier Excel et je dois travailler avec ce que j'ai. Le tri selon l’une des colonnes existantes rompra la séquence.

S'il vous plaît, aidez-nous.

P.S. En fin de compte, l'insertion de la colonne ID dans la feuille de calcul semble indiquer qu'il est impossible de conserver l'ordre lors de l'exportation / importation

Était-ce utile?

La solution

Je ne pense pas que l'ordre des lignes soit spécifié ou garanti par SQL à moins que vous n'utilisiez un "ORDER BY". clause.

D'après un billet de Bill Vaughn ( http://betav.com/ blog / billva / 2008/08 / sql_server_indexing_tips_and_t.html ):

  

Utilisation de Order By: même lorsqu'une table a   un index clusterisé (qui stocke le   données dans l'ordre physique), SQL Server   ne garantit pas que les lignes seront   retourné dans ce (ou tout particulier)   commander sauf si une clause ORDER BY est   utilisé.

Un autre lien avec info:

http://sqlblogcasts.com/blogs/simons/archive/2007/08/21/What-is-the-position-of-a-row--.aspx

Autres conseils

Après de nombreuses recherches, il apparaît évident qu'il est impossible de conserver l'ordre des lignes avec la commande Insertion en bloc écrite telle qu'elle est présentée par Microsoft. Vous devez soit ajouter vous-même une colonne ID directement dans le fichier d'importation, utiliser un shell ou un autre script externe, ou vous en passez. Il semble que ce soit une fonctionnalité nécessaire (et facile) à ajouter par Microsoft, mais cela ne se produira pas après plus de dix ans d'absence.

Pourtant, je devais conserver l'ordre actuel des enregistrements dans le fichier d'importation après avoir importé, car les enregistrements les plus élevés remplaceraient les enregistrements les plus bas si une colonne de l'ensemble avait la même valeur.

J'ai donc emprunté un itinéraire différent. Mes contraintes étaient:

  • Je ne pouvais pas du tout changer le fichier source. (et créer un mauvais précédent!)
  • Je ne pouvais pas utiliser de script externe. Trop compliqué. Ce devait être une solution simple basée sur T-Sql, pas d'exécutions CMD. Cela devait faire l'objet d'une procédure unique pour pouvoir être automatisé.

J'ai aimé la logique d'utiliser Powershell pour créer des instructions d'insertion ordonnées pour chaque ligne, puis de les exécuter en SQL. Il s'agissait essentiellement de mettre chaque enregistrement en file d'attente pour chaque insertion plutôt que pour l'insertion en bloc. Oui, cela fonctionnerait, mais ce serait aussi très lent. J'ai souvent des fichiers avec 500K + lignes en eux. J'avais besoin de quelque chose de rapide.

J'ai donc rencontré XML. Importez en bloc le fichier directement dans une seule variable XML. Cela conserverait l'ordre des enregistrements au fur et à mesure que chacun d'eux est ajouté au XML. Ensuite, analysez la variable XML et insérez les résultats dans une table en ajoutant une colonne d'identité en même temps.

Il est supposé que le fichier d'importation est un fichier texte standard, chaque enregistrement se terminant par un saut de ligne (Char (13) + Char (10))

Mon approche comporte 2 étapes:

  1. Exécutez l'instruction IMPORT SQL (à l'aide de OPENROWSET) en encapsulant chaque enregistrement avec des balises XML. Capturez les résultats dans une variable XML.

  2. Analyser la variable à l'aide des balises XML dans une table en ajoutant une colonne [ID] incrémentante.

    ---------------------------------
    Declare @X xml;
    ---------------------------------
    SELECT @X=Cast('<X>'+Replace([BulkColumn],Char(13)+Char(10),'</X><X>')+'</X>' as XML)
    FROM OPENROWSET (BULK N'\\FileServer\ImportFolder\ImportFile_20170120.csv',SINGLE_CLOB) T
    ---------------------------------
    SELECT [Record].[X].query('.').value('.','varchar(max)') [Record]
    ,ROW_NUMBER() OVER (ORDER BY (SELECT 100)) [ID]
    --Into #TEMP 
    FROM @X.nodes('X') [Record](X);
    ---------------------------------
    
    • Les balises XML remplacent chaque saut de ligne.

    • Si le fichier se termine par un saut de ligne, une ligne vide sera ajoutée à la fin. Supprimez simplement la dernière ligne.

J'ai écrit cela dans ma procédure à l'aide de SQL dynamique afin de pouvoir passer le nom de fichier et de définir l'ID de manière qu'il commence à 1 ou à 0 (s'il existe une ligne d'en-tête).

J'ai pu exécuter cette opération sur un fichier de 300 000 enregistrements en environ 5 secondes.

Vous pourriez également être en mesure de définir une colonne d'identité dans votre table qui s'incrémente automatiquement pendant le chargement des données. De cette façon, vous pourrez effectuer un tri plus tard si vous souhaitez que les enregistrements soient à nouveau dans le même ordre.

Si vous pouvez enregistrer la feuille de calcul Excel au format CSV, il est très facile de générer une liste d'instructions INSERT avec n'importe quel langage de script qui sera exécuté dans le même ordre que la feuille de calcul. Voici un exemple rapide dans Groovy, mais n’importe quel langage de script le fera aussi facilement, sinon plus facilement:

def file1 = new File('c:\\temp\\yourSpreadsheet.csv')
def file2 = new File('c:\\temp\\yourInsertScript.sql')

def reader = new FileReader(file1)
def writer = new FileWriter(file2)

reader.transformLine(writer) { line ->
    fields =  line.split(',')

    text = """INSERT INTO table1 (col1, col2, col3) VALUES ('${fields[0]}', '${fields[1]}', '${fields[2]}');"""

}

Vous pouvez ensuite exécuter votre " yourInsertScript.sql " contre votre base de données et votre commande sera la même que votre feuille de calcul.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top