11

Excel スプレッドシートにアクセスし、スプレッドシートのデータを SQL データベースに挿入する必要があります。ただし、主キーは混在しており、ほとんどが数値で、一部は英数字です。

私が抱えている問題は、数値キーと英数字キーが同じスプレッドシートにある場合、英数字セルは空白の値を返しますが、他のすべてのセルは問題なくデータを返すことです。

OleDb メソッドを使用して Excel ファイルにアクセスしています。コマンド文字列でデータを取得した後、データを DataAdapter に入れ、DataSet に入力します。DataSet の最初の DataTable のすべての行 (dr) を反復処理します。

dr["..."].ToString() を使用して列を参照します

Visual Studio 2008 でプロジェクトをデバッグし、「拡張プロパティ」を表示すると、マウスを「dr」の上に置くことで DataRow の値を表示できますが、英数字である必要がある主キーは {} です。他の値は引用符で囲まれていますが、空白の値には中かっこがあります。

これは C# の問題ですか、それとも Excel の問題ですか?

誰かが以前にこの問題に遭遇したことがありますか、または回避策/修正を見つけましたか?

前もって感謝します。

4

10 に答える 10

27

解決:

接続文字列:

Provider=Microsoft.Jet.OLEDB.4.0;Data Source=FilePath;Extended Properties="Excel 8.0;HDR=はい;IMEX=1";

  1. HDR=Yes;最初の行にデータではなく列名が含まれていることを示します。HDR=No;反対を示しま​​す。

  2. IMEX=1;は、「混合」(数値、日付、文字列など) のデータ列を常にテキストとして読み取るようにドライバーに指示します。このオプションは、Excel シートの書き込みアクセス ネガティブに影響を与える可能性があることに注意してください。

SQL 構文SELECT * FROM [sheet1$]。つまり、Excel ワークシート名の後に a が続き$[ ]括弧で囲まれます。

重要:

  • [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Excel] にあるレジストリ REG_DWORD "TypeGuessRows" を確認してください。これは、Excel が最初の 8 行だけを使用して列のデータ型を推測できないようにするための鍵です。すべての行をスキャンするには、この値を 0 に設定します。これにより、パフォーマンスが低下する可能性があります。

  • Excel ブックがパスワードで保護されている場合、接続文字列に正しいパスワードを指定しても、データ アクセス用にブックを開くことはできません。試行すると、次のエラー メッセージが表示されます。「ファイルを復号化できませんでした。」

于 2009-08-10T04:41:57.913 に答える
1

{}は、これが文字列ではなく、ある種の空のオブジェクトであることを意味します。オブジェクトにカーソルを合わせると、そのタイプが表示されます。同様に、クイックウォッチを使用してdr ["..."]を表示すると、オブジェクトタイプが表示されます。受け取るオブジェクトの種類は何ですか?

于 2008-11-18T14:35:42.377 に答える
1

xlsファイルのレコードをASCIIコードで降順に並べ替えて、英数字フィールドがヘッダー行の下の上部に表示されるようにします。これにより、読み取られたデータの最初の行でデータ型が「varchar」または「nvarchar」として定義されます。

于 2011-10-25T16:40:03.750 に答える
1

ここで同様の質問に答えました。便宜上、同じ回答をコピーして貼り付けました。

私もこれと同じ問題を抱えていましたが、Excel COM インターフェイスやサード パーティ ソフトウェアに頼らずに回避できました。少し処理のオーバーヘッドがかかりますが、私にとってはうまくいっているようです。

  1. 最初にデータを読み取って列名を取得します
  2. 次に、これらの各列で新しい DataSet を作成し、各 DataType を文字列に設定します。
  3. この新しいデータセットにデータを再度読み込みます。出来上がり - 科学表記法はなくなり、すべてが文字列として読み込まれます。

これを説明するコードを次に示します。追加のボーナスとして、StyleCopped です。

public void ImportSpreadsheet(string path)
{
    string extendedProperties = "Excel 12.0;HDR=YES;IMEX=1";
    string connectionString = string.Format(
        CultureInfo.CurrentCulture,
        "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"{1}\"",
        path,
        extendedProperties);

    using (OleDbConnection connection = new OleDbConnection(connectionString))
    {
        using (OleDbCommand command = connection.CreateCommand())
        {
            command.CommandText = "SELECT * FROM [Worksheet1$]";
            connection.Open();

            using (OleDbDataAdapter adapter = new OleDbDataAdapter(command))
            using (DataSet columnDataSet = new DataSet())
            using (DataSet dataSet = new DataSet())
            {
                columnDataSet.Locale = CultureInfo.CurrentCulture;
                adapter.Fill(columnDataSet);

                if (columnDataSet.Tables.Count == 1)
                {
                    var worksheet = columnDataSet.Tables[0];

                    // Now that we have a valid worksheet read in, with column names, we can create a
                    // new DataSet with a table that has preset columns that are all of type string.
                    // This fixes a problem where the OLEDB provider is trying to guess the data types
                    // of the cells and strange data appears, such as scientific notation on some cells.
                    dataSet.Tables.Add("WorksheetData");
                    DataTable tempTable = dataSet.Tables[0];

                    foreach (DataColumn column in worksheet.Columns)
                    {
                        tempTable.Columns.Add(column.ColumnName, typeof(string));
                    }

                    adapter.Fill(dataSet, "WorksheetData");

                    if (dataSet.Tables.Count == 1)
                    {
                        worksheet = dataSet.Tables[0];

                        foreach (var row in worksheet.Rows)
                        {
                            // TODO: Consume some data.
                        }
                    }
                }
            }
        }
    }
}
于 2010-09-09T16:18:10.303 に答える
1

解決:

  1. 最初の行が列ヘッダーと見なされないように、HDR=No を設定します。接続文字列: Provider=Microsoft.Jet.OLEDB.4.0;Data Source=FilePath;Extended Properties="Excel 8.0;HDR=No;IMEX=1";
  2. 最初の行を無視し、任意の方法 (DataTable、DataReader など) でデータにアクセスします。列名ではなく、数値インデックスで列にアクセスします。

それは私のために働いた。この方法では、レジスタを変更する必要はありません!

于 2009-09-03T09:53:14.103 に答える
1

VISTA との互換性のために、接続文字列で EXCEL 12.0 ドライバーを使用できます。これで問題が解決するはずです。それは私のものでした。

于 2009-02-18T15:49:51.520 に答える
1

ItemArray はオブジェクト配列です。したがって、参照しようとしている DataRow の「列」はオブジェクト型であると想定しています。

于 2008-11-19T04:48:56.743 に答える
0

これは完全に正しくありません。どうやら、IMEX=1 に関係なく、最初の 8 行が空白の場合、Jet/ACE は常に文字列型であると見なします。レジストリで行を 0 に読み取らせても、同じ問題が発生しました。これは、それを機能させる唯一の確実な方法でした。

try
{
    Console.Write(wsReader.GetDouble(j).ToString());
}
catch   //Lame unfixable bug
{
    Console.Write(wsReader.GetString(j));
}

于 2012-07-16T19:49:53.693 に答える
0

こんにちは、このコードはすべて英数字の値も取得します

using System.Data.OleDb;

string ConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + filepath + ";" + "Extended Properties="+(char)34+"Excel 8.0;IMEX=1;"+(char)34;

string CommandText = "select * from [Sheet1$]";

OleDbConnection myConnection = new OleDbConnection(ConnectionString);
myConnection.Open();

OleDbDataAdapter myAdapter = new OleDbDataAdapter(CommandText, myConnection);

ds = null;
ds = new DataSet();
myAdapter.Fill(ds);
于 2011-05-13T08:48:35.433 に答える