none
SqlCommand.executeNonQuery()によるINSERT-SELECT文発行に伴うNULL値を登録するDate型Null許可項目に1900/1/1が登録される RRS feed

  • 質問

  • ご質問させてください。

    開発環境)

     開発言語:C#

     データベース:SQLServer2016

    INSERT-SELECT文のSQLをSqlCommand.ExecuteNonQuery()メソッドを利用して実行したところ、想定しないDate型データ(1900/1/1)が設定されてしまった。

    INSERT先テーブルのDate型項目はNull値を許可しており、NULL値を想定していたが、登録先のDate型項目と対応するSELECT先のテーブルの項目は文字列型のNull値許可のカラムであり、NULLがすでに入っている状態です。

    SMSツールなどを利用して同じINSERT-SELECT文を実行すると対象のDate型項目には想定のNULL値が設定されますが、ExecuteNonQuery()メソッドによるINSERT-SELECT文を実行すると1900/1/1の日付が登録されてしまいます。

    問題点や、原因などご教示ください。

    2019年9月11日 10:18

回答

  • 回答者・閲覧者が問題を再現できる必要最低限の情報(DB のテーブルのスキーマや ADO.NET のコードのサンプル)を書けませんか?
    • 回答としてマーク staka.winner 2019年9月12日 3:07
    2019年9月11日 12:36
  • SQL ServerプロファイラでどのようなSQLが発行されているのか確かめるのも手です。
    勝手に1900/1/1が登録されることはないので、何かしらどこかで設定しているはずです。

    ★良い回答には質問者は回答済みマークを、閲覧者は投票を!

    • 回答としてマーク staka.winner 2019年9月12日 2:29
    2019年9月12日 2:26

すべての返信

  • 回答者・閲覧者が問題を再現できる必要最低限の情報(DB のテーブルのスキーマや ADO.NET のコードのサンプル)を書けませんか?
    • 回答としてマーク staka.winner 2019年9月12日 3:07
    2019年9月11日 12:36
  • ご回答ありがとうございます。

    実コードは開示できないので、サンプルを作成し実施したところちゃんとNULLが登録されました。

    以下がサンプルコードです。

                string sql = @"INSERT INTO T_DESTINATION (DATE01D) SELECT DATE01S FROM T_SOURCE";
                using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.CONNECTION_STRING))
                {
                    conn.Open();
                    using (SqlTransaction tran = conn.BeginTransaction(IsolationLevel.Serializable))
                    {
                        try
                        {
                            SqlCommand cmd = tran.Connection.CreateCommand();
                            cmd.Transaction = tran;
                            cmd.CommandText = sql;
                            int ret = cmd.ExecuteNonQuery();
                            tran.Commit();

                            Console.WriteLine($"ret = {ret}");
                        }
                        catch (Exception)
                        {
                            tran.Rollback();
                            throw;
                        }
                    }
                }

    T_DESTINATIONテーブルにはDATE型NULL可のDATE01Dカラム、

    T_SOURCEテーブルにはNVARCHAR(256)型NULL可のDATE01Sカラム

    もう少し実コードの内容を検証してみます。

    2019年9月12日 2:11
  • SQL ServerプロファイラでどのようなSQLが発行されているのか確かめるのも手です。
    勝手に1900/1/1が登録されることはないので、何かしらどこかで設定しているはずです。

    ★良い回答には質問者は回答済みマークを、閲覧者は投票を!

    • 回答としてマーク staka.winner 2019年9月12日 2:29
    2019年9月12日 2:26
  • ありがとうございます。

    確認してみます。

    2019年9月12日 3:00
  • 再度、実コードを検証した結果、テストコードの内容に問題がありました。

    T_SOURCEテーブルのDATE01SカラムにNULL値を設定しているつもりでおりましたが、

    0サイズの文字列を設定しておりました。

    今回は、テストコードの見直しも含め他コードへの影響も再確認させていただく良い機会ともなりました。

    色々、ご指摘していただいた皆さんありがとうございました。


    2019年9月12日 3:07
  • 上のコードはサンプルなので省略したのかもしれませんが、SQL インジェクション防止と性能向上のためクエリは必ずパラメータ化することをお勧めします。

    ひょっとしたらパラメータ化の副次的な効用があって、フレームワークが "" または null を DBNull.Value に変換して INSERT してくれるということも期待できるかもしれません。
    2019年9月12日 3:43
  • ご指摘ありがとうございます。

    その通りですね、ご指摘の通り実コードのほうはSQLインジェクション対策を取っております。

    上記のような場合のフレームワークの選定・仕様調査も重要ですね。

    アドバイスありがとうございます。

    2019年9月12日 10:20