2012-05-23 2 views
1

Tout, j'ai un utilitaire pour exporter DataTables vers Excel (en tous les deux .xls et les types de fichiers .xlsx). Lorsque j'atteins une limite de colonne ou de ligne sur le DataTable (extrait de SQL Server), je veux diviser le DataTable en enfants, chacun respectant les limites (pour les .xls 256 colonnes et 65 536 lignes et .xlsx 16 384 colonnes et 1 048 576 lignes) .Fractionner un DataTable dans plusieurs DataTables

Jusqu'à présent, j'ai écrit la méthode suivante pour faire ce que je veux

public static List<DataTable> SplitDataTable(DataTable mother, int nColLimit) 
{ 
    List<int[]> rangeList = new List<int[]>(); 
    int primaryCols = mother.Columns.Count; 
    int nSplitCount = Convert.ToInt32(primaryCols/nColLimit); 
    int max = -1; 

    // Get the child ranges. 
    int tmpSup = 0; 
    for (int splits = 0; splits < nSplitCount; splits++) 
    { 
     if (rangeList.Count == 0) 
      tmpSup = (splits + 1) * (nColLimit - 1); 
     else 
      tmpSup = rangeList[splits - 1][1] + nColLimit; 
     rangeList.Add(new int[2] { splits * nColLimit, tmpSup }); 
     if (max < tmpSup) 
      max = tmpSup; 
    } 
    rangeList.Add(new int[2] { ++max, primaryCols }); 

    // Build child DataTables. 
    List<DataTable> childList = new List<DataTable>(); 
    int childIndex = 0; 
    foreach (int[] range in rangeList) 
    { 
     childList.Add(new DataTable()); 
     for (int i = range[0]; i < range[1]; i++) 
      for (int j = 0; j < mother.Rows.Count; j++) 
       childList[childIndex].Rows[j][i] = mother.Rows[j][i]; 
     childIndex++; 
    } 
    return childList; 
} 

Ceci, cependant, un indexOutOfRangeException jette avec le message « Il n'y a pas de ligne à la position 0. ». J'apprécie d'où vient l'erreur, mais quelle est la meilleure façon de copier les colonnes complètes du mother à un enfant?

J'ai aussi essayé

List<DataTable> childList = new List<DataTable>(); 
int childIndex = 0; 
foreach (int[] range in rangeList) 
{ 
    childList.Add(new DataTable()); 
    foreach(DataRow row in mother.Rows) 
    { 
     DataRow tmpRow = childList[childIndex].NewRow(); 
     for (int i = range[0]; i < range[1]; i++) 
      tmpRow[i + 1] = row[i + 1]; 
    } 
    childIndex++; 
} 

qui donnent la même exception de gamme.

Merci pour votre temps.

Edit: comment je l'ai fait à court terme

foreach (int[] range in rangeList) 
{ 
    childList.Add(new DataTable()); 
    string strSqlTmp = 
    String.Format("declare @columns varchar(max) " + 
     "select @columns = case when @columns is null " + 
     "then '' " + 
     "else @columns + ', ' " + 
     "end + name " + 
      "from sys.columns " + 
      "where object_id = object_id('{0}') and name in " + 
       "(SELECT COLUMN_NAME " + 
        "FROM [{1}].INFORMATION_SCHEMA.COLUMNS " + 
        "WHERE TABLE_NAME = N'{0}' " + 
        "AND ORDINAL_POSITION > {2} AND ORDINAL_POSITION < {3}) " + 
     "declare @query varchar(max) " + 
     "set @query = 'select ' + @columns + ' from {0}' " + 
     "exec (@query); 
    // Then get each DataTable from SQL Server and fill the child list... 

Répondre

1

La raison pour laquelle vous obtenez l'exception IndexOutOfRange est parce que vous essayez de référence Column s dans votre nouvelle DataTable qui n'existent pas. Cette ligne:

childList.Add(new DataTable()); 

n'ajoute en effet une nouvelle DataTable-childList, mais DataTable n'a pas de colonnes et de lignes.

Normalement je pourrais utiliser la méthode DataTable.Clone() pour créer une nouvelle DataTable avec la même structure que la DataTable la méthode a été appelée, mais de toute évidence cela ne fonctionnera pas pour vous. Dans votre cas, vous devrez ajouter explicitement DataColumn en utilisant la méthode DataTable.Columns.Add.

Quelque chose comme:

for (int i = 0; i < numberOfColumns; i++) { 
    dataTable.Columns.Add(string.Format("Column {0}", i)); 
} 

L'extrait ci-dessus est très simpliste. Puisque vous allez créer le DataColumn s vous-même, vous devrez nommer et taper chacun des DataColumn.

+0

Merci beaucoup pour votre temps. Pendant ce temps, j'ai skimpé et demandé à SQL Server de le faire. J'ai édité ma question pour montrer comment ceci a été fait si vous avez intéressé ... – MoonKnight

+0

heureux que vous l'ayez fonctionné et merci pour signaler votre solution. –

1

Je viens de créer une méthode de fractionnement d'une table de données. La méthode ".Batch" est référencée à partir de MoreLinq.

private static List<DataTable> SplitTable(DataTable originalTable, int batchSize) 
     { 
      List<DataTable> tables = new List<DataTable>(); 

      foreach (var rowBatch in originalTable.Rows.Cast<DataRow>().Batch(batchSize)) 
      { 
       var batchTable = new DataTable(originalTable.TableName); 

       foreach (DataColumn column in originalTable.Columns) 
        batchTable.Columns.Add(column.ColumnName, column.DataType); 

       foreach (DataRow row in rowBatch) 
        batchTable.Rows.Add(row.ItemArray); 

       tables.Add(batchTable); 
      } 
      return tables; 
     } 

Juste au cas où ce serait utile à tout le monde :)

Questions connexes