web-dev-qa-db-ja.com

SqlBulkCopyが機能しない

ExcelシートからDataSetを入力しました。 SQLBulkコピーを使用してLead_Hdrテーブルにレコードを挿入したかったのですが、LeadIdはPKです。

以下のコードの実行中に次のエラーが発生します:

指定されたColumnMappingは、ソースまたは宛先のどの列とも一致しません

string ConStr=ConfigurationManager.ConnectionStrings["ConStr"].ToString();

using (SqlBulkCopy s = new SqlBulkCopy(ConStr,SqlBulkCopyOptions.KeepIdentity))
{
    if (MySql.State==ConnectionState.Closed)
    {
        MySql.Open();
    }

    s.DestinationTableName = "PCRM_Lead_Hdr";
    s.NotifyAfter = 10000;

    #region Comment
    s.ColumnMappings.Clear();

    #region ColumnMapping
    s.ColumnMappings.Add("ClientID", "ClientID");
    s.ColumnMappings.Add("LeadID", "LeadID");
    s.ColumnMappings.Add("Company_Name", "Company_Name");
    s.ColumnMappings.Add("Website", "Website");
    s.ColumnMappings.Add("EmployeeCount", "EmployeeCount");
    s.ColumnMappings.Add("Revenue", "Revenue");
    s.ColumnMappings.Add("Address", "Address");
    s.ColumnMappings.Add("City", "City");

    s.ColumnMappings.Add("State", "State");
    s.ColumnMappings.Add("ZipCode", "ZipCode");
    s.ColumnMappings.Add("CountryId", "CountryId");

    s.ColumnMappings.Add("Phone", "Phone");
    s.ColumnMappings.Add("Fax", "Fax");
    s.ColumnMappings.Add("TimeZone", "TimeZone");
    s.ColumnMappings.Add("SicNo", "SicNo");
    s.ColumnMappings.Add("SicDesc", "SicDesc");

    s.ColumnMappings.Add("SourceID", "SourceID");
    s.ColumnMappings.Add("ResearchAnalysis", "ResearchAnalysis");
    s.ColumnMappings.Add("BasketID", "BasketID");
    s.ColumnMappings.Add("PipeLineStatusId", "PipeLineStatusId");

    s.ColumnMappings.Add("SurveyId", "SurveyId");
    s.ColumnMappings.Add("NextCallDate", "NextCallDate");
    s.ColumnMappings.Add("CurrentRecStatus", "CurrentRecStatus");
    s.ColumnMappings.Add("AssignedUserId", "AssignedUserId");
    s.ColumnMappings.Add("AssignedDate", "AssignedDate");
    s.ColumnMappings.Add("ToValueAmt", "ToValueAmt");
    s.ColumnMappings.Add("Remove", "Remove");
    s.ColumnMappings.Add("Release", "Release");

    s.ColumnMappings.Add("Insert_Date", "Insert_Date");
    s.ColumnMappings.Add("Insert_By", "Insert_By");
    s.ColumnMappings.Add("Updated_Date", "Updated_Date");
    s.ColumnMappings.Add("Updated_By", "Updated_By");

    #endregion
    #endregion

    s.WriteToServer(sourceTable);

    s.Close();

    MySql.Close();
}
20
Sandhurst

さて、そうですか?列名は両側に存在しますか?

正直なところ、私はマッピングに悩まされたことはありません。私は物事をシンプルに保つのが好きです-私はサーバー上の入力のように見えるステージングテーブルを持っている傾向があり、次にステージングテーブルにSqlBulkCopyし、最後にストアドプロシージャを実行してテーブルをステージングテーブルから移動します実際のテーブルに;利点:

  • インポートがいずれかの時点で失敗した場合でも、ライブデータの破損に関する問題はありません
  • SPROCの周りにトランザクションを置くことができます
  • SPROCがログに記録されることを知っていれば、ログを記録せずにbcpを機能させることができます。
  • それは単純です;-p(マッピングをいじることはありません)

最後に、バルクデータを処理している場合は、IDataReaderを使用してスループットを向上させることができます(これはストリーミングAPIであるため、DataTableはバッファリングされたAPIです)。たとえば、私はSqlBulkCopyのソースとして CsvReader を使用してCSVインポートをフックする傾向があります。または、XmlReaderの周りにシムを記述して、各第1レベルの要素をIDataReaderの行として非常に高速に表示します。

22
Marc Gravell

SQLSERVER 2005へのアクセスからデータをコピーしているときに同じ問題が発生しましたが、データベースの機密性に関係なく、両方のデータソースで列のマッピングで大文字と小文字が区別されることがわかりました。

40
Tareq

理由の1つは、:SqlBukCOpyでは大文字と小文字が区別されることです。次の手順に従います。

  1. その場合、最初にC#の「Contain」メソッドを使用してソーステーブルで列を見つける必要があります。
  2. Destination列がsource列と一致したら、その列のインデックスを取得し、SqlBukCOpyでその列名を指定します。

例: `

//Get Column from Source table 
  string sourceTableQuery = "Select top 1 * from sourceTable";
   DataTable dtSource=SQLHelper.SqlHelper.ExecuteDataset(transaction, CommandType.Text, sourceTableQuery).Tables[0];// i use sql helper for executing query you can use corde sw

 for (int i = 0; i < destinationTable.Columns.Count; i++)
                        {    //check if destination Column Exists in Source table
                            if (dtSource.Columns.Contains(destinationTable.Columns[i].ToString()))//contain method is not case sensitive
                            {
                                int sourceColumnIndex = dtSource.Columns.IndexOf(destinationTable.Columns[i].ToString());//Once column matched get its index
                                bulkCopy.ColumnMappings.Add(dtSource.Columns[sourceColumnIndex].ToString(), dtSource.Columns[sourceColumnIndex].ToString());//give coluns name of source table rather then destination table so that it would avoid case sensitivity
                            }

                        }
                        bulkCopy.WriteToServer(destinationTable);
                        bulkCopy.Close();
2
Asad

マークによる答えは、(ステージングテーブルの使用に関する)私の推奨事項です。これにより、ソースが変更されない場合、将来のインポートの問題が少なくなります。

ただし、私の経験では、次の問題を確認できます。

ソースとテーブルで列名が一致する列タイプが一致すること

あなたがこれをしたと思うが、それでも成功しない場合。以下を試すことができます。

1-テーブルのすべての列でnullを許可します2-すべての列マッピングをコメントアウトします3-問題がどこにあるかが見つかるまで、一度に1列ずつ追加して再実行します

それはバグを引き出すはずです

2
Tony Basallo

答えることについて長い間考えていました...列名が同じ場合でも、データ型が異なると同じエラーが発生します。したがって、列名とそのデータ型を確認してください。

追伸:ステージングテーブルは、インポートするための決定的な方法です。

0
jocheng

私が見つけたのは、テーブルの列と入力の列が少なくとも一致している必要があるということです。テーブルにさらに列を含めることができ、入力は引き続きロードされます。少ない場合はエラーが発生します。

0
Rich

ステージングのアイデアを採用しますが、大文字と小文字を区別する性質を処理するための私のアプローチは次のとおりです。私のlinqで批評されて幸せ

using (SqlConnection connection = new SqlConnection(conn_str))
{
        connection.Open();
        using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
        {
            bulkCopy.DestinationTableName = string.Format("[{0}].[{1}].[{2}]", targetDatabase, targetSchema, targetTable);
            var targetColumsAvailable = GetSchema(conn_str, targetTable).ToArray();
            foreach (var column in dt.Columns)
            {
                if (targetColumsAvailable.Select(x => x.ToUpper()).Contains(column.ToString().ToUpper()))
                {
                    var tc = targetColumsAvailable.Single(x => String.Equals(x, column.ToString(), StringComparison.CurrentCultureIgnoreCase));
                    bulkCopy.ColumnMappings.Add(column.ToString(), tc);
                }
            }

            // Write from the source to the destination.
            bulkCopy.WriteToServer(dt);
            bulkCopy.Close();
        }
}

とヘルパーメソッド

private static IEnumerable<string> GetSchema(string connectionString, string tableName)
        {



   using (SqlConnection connection = new SqlConnection(connectionString))
        using (SqlCommand command = connection.CreateCommand())
        {
            command.CommandText = "sp_Columns";
            command.CommandType = CommandType.StoredProcedure;

            command.Parameters.Add("@table_name", SqlDbType.NVarChar, 384).Value = tableName;

            connection.Open();
            using (var reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    yield return (string)reader["column_name"];
                }
            }
        }
    }
0
Dickster