2012-05-01 10 views
22

Mam Data Data i potrzebuję całej rzeczy pchanej do tabeli bazy danych.Wstaw całą tabelę danych do bazy danych za jednym razem zamiast wiersz po wierszu?

Mogę dostać to wszystko tam z foreach i wstawianie każdego rzędu na raz. Jest to jednak bardzo powolne, ponieważ istnieje kilka tysięcy wierszy.

Czy istnieje sposób na wykonanie całego zestawu danych jednocześnie, który może być szybszy?

DataTable ma mniej kolumn niż tabela SQL. reszta z nich powinna pozostać NULL.

+4

SqlBulkCopy jest zdecydowanie droga –

+0

http://www.codedigest.com/Articles/Framework/388_Doing_Bulk_UploadInsert_of_DataTable_to_a_Table_in_SQL_server_in_C_.aspx dla SqlBulkCopy przykład. – JamieSee

+2

Czy możesz określić, która wersja SQL Server? –

Odpowiedz

48

Odkryłem, że SqlBulkCopy jest prostym sposobem na zrobienie tego i nie wymaga zapisywania procedury zapisanej w SQL Server.

Oto przykład jak I wdrożone go:

// take note of SqlBulkCopyOptions.KeepIdentity , you may or may not want to use this for your situation. 

using (var bulkCopy = new SqlBulkCopy(_connection.ConnectionString, SqlBulkCopyOptions.KeepIdentity)) 
{ 
     // my DataTable column names match my SQL Column names, so I simply made this loop. However if your column names don't match, just pass in which datatable name matches the SQL column name in Column Mappings 
     foreach (DataColumn col in table.Columns) 
     { 
      bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName); 
     } 

     bulkCopy.BulkCopyTimeout = 600; 
     bulkCopy.DestinationTableName = destinationTableName; 
     bulkCopy.WriteToServer(table); 
} 
+4

@AaronBertrand Miałem poprzednią odpowiedź, która była po prostu "SQL Bulk Copy", bez szczegółów. Usunąłem go i zastąpiłem tym szczegółowym. W wielu sytuacjach nie jest źle, aby uzyskać SP, w niektórych jest. Nigdy nie twierdziłem, że jest źle, po prostu oferuję rozwiązanie, które tego nie wymaga. – Kyle

+0

Dla potomności należy edytować taką odpowiedź, zamiast ją usuwać i publikować nową. Wtedy jest bardziej intuicyjny dla innych, skąd pochodzi ta nowa odpowiedź. –

+6

Nie jestem pewien, skąd pochodzi odpowiedź na pytania, jeśli nie ma w niej użytecznych informacji. Powodem, dla którego zrobiłem nowy, było to, że komentarz nie miał już sensu z odnowioną odpowiedzią i nie miał znaczenia dla pytania. – Kyle

27

Skoro masz już DataTable, a ponieważ jestem zakładając używasz SQL Server 2008 lub lepsze, jest to prawdopodobnie najprostszy sposób. Po pierwsze, w swojej bazie danych, należy utworzyć dwa następujące obiekty:

CREATE TYPE dbo.MyDataTable -- you can be more speciifc here 
AS TABLE 
(
    col1 INT, 
    col2 DATETIME 
    -- etc etc. The columns you have in your data table. 
); 
GO 

CREATE PROCEDURE dbo.InsertMyDataTable 
    @dt AS dbo.MyDataTable READONLY 
AS 
BEGIN 
    SET NOCOUNT ON; 

    INSERT dbo.RealTable(column list) SELECT column list FROM @dt; 
END 
GO 

Teraz w kod C#:

DataTable tvp = new DataTable(); 
// define/populate DataTable 

using (connectionObject) 
{ 
    SqlCommand cmd = new SqlCommand("dbo.InsertMyDataTable", connectionObject); 
    cmd.CommandType = CommandType.StoredProcedure; 
    SqlParameter tvparam = cmd.Parameters.AddWithValue("@dt", tvp); 
    tvparam.SqlDbType = SqlDbType.Structured; 
    cmd.ExecuteNonQuery(); 
} 

Jeśli dał więcej szczegółów w swoim pytaniu, dałbym bardziej szczegółowy odpowiedź.

+0

Jeśli się nie mylę, to będzie działać przyzwoicie tylko dla stosunkowo niewielkich ilości danych, ponieważ @d będzie zapełniane wiersz po wierszu. 'SqlBulkCopy' jest o wiele bardziej wydajne dla dużych danych (tysiące i więcej). – Alexei

+0

@Aaron Bertrand Mam ponad 600000 wstawień rekordów dla 3 różnych stołów. Tabela A nie jest zależna od żadnej innej tabeli, podczas gdy tabela B wymaga klucza podstawowego z tabeli A, a tabela C wymaga klucza podstawowego z A i B. Również tabela D wymaga aktualizacji 10000 rekordów. Jak mogę to osiągnąć. – User

0

wolałbym zdefiniowane przez użytkownika typ danych: jest super szybki.

Etap 1: własnego definiowania Tabela w SQL serwera bazy

CREATE TYPE [dbo].[udtProduct] AS TABLE(
    [ProductID] [int] NULL, 
    [ProductName] [varchar](50) NULL, 
    [ProductCode] [varchar](10) NULL 
) 
GO 

Etap 2: Tworzenie procedury przechowywanej z typ zdefiniowany przez użytkownika

CREATE PROCEDURE ProductBulkInsertion 
@product udtProduct readonly 
AS 
BEGIN 
    INSERT INTO Product 
    (ProductID,ProductName,ProductCode) 
    SELECT ProductID,ProductName,ProductCode 
    FROM @product 
END 

Etapie 3: Wykonaj procedurę przechowywaną z C#

SqlCommand sqlcmd = new SqlCommand("ProductBulkInsertion", sqlcon); 
sqlcmd.CommandType = CommandType.StoredProcedure; 
sqlcmd.Parameters.AddWithValue("@product", productTable); 
sqlcmd.ExecuteNonQuery(); 

Możliwa Problem: Alter User Defined Tabela

Właściwie nie ma polecenia SQL Server, aby zmienić zdefiniowane przez użytkownika typ Ale w Management Studio można to osiągnąć z następujących etapów

1. wygeneruj skrypt dla danego typu. (W nowym oknie zapytania lub jako plik). 2. Usuń tabelę użytkownika z usuniętymi błędami. 3. Zmodyfikuj skrypt tworzenia, a następnie wykonaj.

1

Jeśli odbiegają nieco od prostej ścieżce DataTable -> tabela SQL, to może być również wykonane za pomocą listy obiektów:

1) DataTable -> Generic lista obiektów

public static DataTable ConvertTo<T>(IList<T> list) 
{ 
    DataTable table = CreateTable<T>(); 
    Type entityType = typeof(T); 
    PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entityType); 

    foreach (T item in list) 
    { 
     DataRow row = table.NewRow(); 

     foreach (PropertyDescriptor prop in properties) 
     { 
      row[prop.Name] = prop.GetValue(item); 
     } 

     table.Rows.Add(row); 
    } 

    return table; 
} 

Źródło i więcej szczegółów można znaleźć here. Właściwości brakujące pozostanie do ich wartości domyślnych (0 dla int s, null dla typów referencyjnych itp)

2) Naciśnij obiektów do bazy danych

Jednym sposobem jest użycie EntityFramework.BulkInsert rozszerzenie. Jednak wymagany jest plik danych EF.

Generuje polecenie BULK INSERT wymagane do szybkiego wstawiania (rozwiązanie typu zdefiniowanego przez użytkownika jest znacznie wolniejsze).

Chociaż nie jest to metoda prosta, pomaga zbudować podstawę pracy z listą obiektów zamiast DataTable s, która jest seems to be much more memory efficient.

3

Rozważmy this approach, nie trzeba pętli for:

using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection)) 
{ 
    bulkCopy.DestinationTableName = 
     "dbo.BulkCopyDemoMatchingColumns"; 

    try 
    { 
     // Write from the source to the destination. 
     bulkCopy.WriteToServer(ExitingSqlTableName); 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex.Message); 
    } 
} 
+0

dla początkujących takich jak ja: bulkCopy.WriteToServer (ExitingSqlTableName); Tutaj ExistingSqlTableName oznacza istniejące źródło danych sql. Może to być tabela sql, datatable lub czytnik. – Goldfish

Powiązane problemy