日付と時刻の2つのデータベースフィールド-マージする必要がありますか?


8

次の質問では、フィールドとテーブルの名前がIDを保護するために変更されています。

2つのデータベース列がある場合:

MONKEY_DATE DATETIME NULL (with data e.g. 2012-05-14 00:00:00.000)
MONKEY_TIME DATETIME NULL (with data e.g. 1753-01-01 16:30:53.025)

時間フィールドの日付コンポーネントは、ほとんどが1753年1月1日に設定されています...しかし、一部のデータは1899年1月1日で、一部は1900年1月1日です。

これらの列をクエリおよびレポートするコードを維持すると、私(および私たちのチーム)は2つの列をマージすることで簡単に解決できる頭痛の種を引き起こします。しかし、経験(およびTerry Goodkind)は、決して簡単なことはないことを教えてくれました。これが頭痛の原因であるいくつかの例を以下に示します。

私のアプローチ

次のアプローチには、2つの列をマージするという望ましい効果があると思います。

  1. SQLを使用してデータを更新し、日付フィールドの値と時間フィールドの値の両方を同じ値に設定します。これは、日付フィールドの日付コンポーネントと時間フィールドの時間コンポーネントの混合です。
  2. MONKEY_DATEフィールドのみを使用して新しいコードを記述します
  3. 最終的にMONKEY_TIMEフィールドと日付/時刻コンポーネントSQLを段階的に廃止します(例を参照)
  4. MONKEY_TIMEをドロップ

これは、すぐに行ってシステム全体に遡及的な変更を加える必要がないことを意味します。既存のコードはすべて引き続き機能します...そして、正しい方法で作業を開始できます。

#1のSQLは(Oracle)の場合があります。

UPDATE MONKEY SET 
    MONKEY_DATE = TO_DATE(TO_CHAR(MONKEY_DATE, 'MM/DD/YYYY ') || 
                      TO_CHAR(MONKEY_TIME, 'HH24:MI:SS'), 
                      'MM/DD/YYYY HH24:MI:SS')
    MONKEY_TIME = TO_DATE(TO_CHAR(MONKEY_DATE, 'MM/DD/YYYY ') || 
                      TO_CHAR(MONKEY_TIME, 'HH24:MI:SS'), 
                      'MM/DD/YYYY HH24:MI:SS')

質問

あなたへの私の質問は:

  • これらのフィールドをマージする必要がありますか?
  • これらの2つの列をマージするための私のアプローチは妥当ですか?
  • ステップ2と3をスキップする方が良いと思いますか?
  • 他に(建設的な)コメントや提案はありますか?

たとえば、サルの日付と時刻をすべて選択し、日付と時刻で並べ替えるには、次のようにする必要があります(SQL Server)。

SELECT 
      CONVERT(DATETIME, CONVERT(VARCHAR, MONKEY_DATE, 101), 101) AS MONKEY_DATE
    , CONVERT(DATETIME, CONVERT(VARCHAR, MONKEY_TIME, 108), 108) AS MONKEY_TIME 
FROM MONKEY 
ORDER BY
      CONVERT(DATETIME, CONVERT(VARCHAR, MONKEY_DATE, 101), 101) DESC
    , CONVERT(DATETIME, CONVERT(VARCHAR, MONKEY_TIME, 108), 108) DESC

またはこれ(Oracle-もう少し明示的):

SELECT
      TO_DATE(TO_CHAR(MONKEY_DATE, 'MM/DD/YYYY'), 'MM/DD/YYYY') AS MONKEY_DATE
    , TO_DATE(TO_CHAR(MONKEY_TIME, 'HH24:MI:SS'), 'HH24:MI:SS') AS MONKEY_TIME
FROM MONKEY
ORDER BY
      TO_DATE(TO_CHAR(MONKEY_DATE, 'MM/DD/YYYY'), 'MM/DD/YYYY') DESC
    , TO_DATE(TO_CHAR(MONKEY_TIME, 'HH24:MI:SS'), 'HH24:MI:SS') DESC

また、結合された日付/時刻列(Oracle)を選択することもあります。

SELECT 
    TO_DATE(TO_CHAR(MONKEY_DATE, 'MM/DD/YYYY ') || 
            TO_CHAR(MONKEY_TIME, 'HH24:MI:SS'), 
        'MM/DD/YYYY HH24:MI:SS') AS MONKEY_DATE_TIME 
FROM MONKEY

いつものように、サルの日付と時刻を知りたいからです。

上記のSQLは次のように簡単に変更できます。

SELECT MONKEY_DATE_TIME FROM MONKEY ORDER BY MONKEY_DATE_TIME

...列をマージした場合のみ。

バックグラウンド

日付と時刻をデータベースの別々の列に格納する古いASPシステムを継承しました。これはおそらく、アプリケーションがAccessの初期バージョンで開始されたため、日付と時刻の両方を同じ列に格納することができなかったためだと言われています。理由と方法はこの質問の一部ではありませんが、知りたい人もいます。

PS

私は本当にこれをSO.SEに投稿するところだったので、間違ったサイトを取得した場合の私の謝罪。


マージをコミットします。コミットしたら-カット!
2012年

回答:


15

1つのマイナーポイント:2つの列をマージする場合、既存の列を上書きするのではなく、新しい「MONKEY_DATE_2」列にマージすることをお勧めします。これにより、現在の列は変更されず、grepを使用した新しい構造で動作するように更新されていないすべてのコードを見つけることができます。


6
+1。それはまさに私が提案しようとしていたことです(例外として、新しい列をMONKEY_DATETIMEと呼びます)。
Doc Brown、

5
また、新しい列が変更されたときに古い列を更新するトリガーを追加することを忘れないでください。
Blrfl

うーん、はい。トリガー。少なくとも斧が落ちるまで... :)
mjfgates '15年

7

はい、統合する必要があると思います。正当な理由がない限り、通常は日付と時刻のフィールドを区切ることはありません。レガシーシステム適切な理由かもしれませんが、日付と時刻を組み合わせて処理できるシステムにデータが移行されている場合は、マージすることをお勧めします。

あなたのアプローチについては、それは合理的に聞こえます。小さなリファクタリングプロジェクトを実行してすべてのコードを同時に修正し、すべてのクエリをまとめて修正して、「最終的にMONKEY_TIMEフィールドを段階的に廃止する」ことを確認することもできますが、時間がかかる場合があります。そしておそらくそれは重要な回帰テストを必要とするでしょう。あなたがそれを前もって計画するなら、それは問題であってはなりません。

また、異なるコードベースから構築されているが、別個の日付と時刻の値に依存しているダウンストリームシステム(Webサービスや外部レポートシステムなど)があるかどうかも調べます。そのようなシステムが存在する場合、それらもこの計画の一部である必要があります。


1
ダウンストリームシステムの場合は+1。チェックが必要なAPIがいくつかあります...うーん、それはAPIを使用するサードパーティシステムに影響を与える可能性があります。私はそれについて考えなければならないでしょう、ありがとう。
オリバークラール

1
はは。どちらの答えも「あなたの*は合理的に聞こえます」と答えています。偉大な心は同じように考える?:P
Oleksi

レガシーシステムが本質的にまだ機能している場合は、それらの日付を参照するコードが適切にラップされ、日付のみまたは適切な場合は時刻のみを参照することを確認してください。
mikebabcock

3

日付と時刻が常に一緒に使用される場合は、必ず、列をマージして、頭痛の少ない利点を享受してください。

注意点:

  • 日の相対時間を計算するための時間列の使用(たとえば、「このサルがバナナに行ったときから1時間以内の任意の日に一度にバナナに行ったサルの選択」)。
  • 小数日を正気に処理しない日付列の算術。
  • グループ化メカニズムとしての日付列の使用。

特にスティッキーな既存のクエリがある場合は、それらを修正できるまで、古い動作をエミュレートする更新可能なビューを作成します。


2

前職でも同様の問題がありました。日付と時刻を2つのDB列に分割します。これは私たちに多くの頭痛の種をもたらしました。> _ <とはいえ、DBで単一の日時列に切り替えることを強くお勧めします。これにより、多くのバグが忍び寄るのを防ぎます。

あなたの戦略に関しては、それは合理的に聞こえますが、チーム全体がこの決定とリファクタリングに関与するようにしてください。古いデータスキーマを使用しないように積極的に取り組む必要があります。

多くのコード変更が必要ない場合(そして、少し時間がある場合!)、一度にすべてを変更し、両方のデータスキーマをサポートする「中間」ステップがないことを検討できます。ただし、これは通常は起こりそうにないので、ステップ2/3で述べたような何らかの移行計画が必要になる可能性があります。


1

(すべての変更を準備してから一度にすべてをインストールするのではなく)この変更を徐々に段階的に進める場合は、古い方法で書かれた新しい方法で値を読み取らないように注意する必要があります。したがって、移行は次のように行う必要があります。

  1. すべての新しい方法は、新しい方法と古い方法の両方を書き込み(新しい方法に新しい列を使用すると効果的です)、古い方法を読み取ります。既存のコードは、新しい方法と古い方法の両方を書き込むように変更されています。

  2. すべてのコードが両方の方法で書き込んだら、既存のデータを変換して両方で利用できるようにします。

  3. すべての新しいコードは新しい方法を読み取ります(両方の方法を書き込みます)。既存のコードは、新しい方法を読み取るように変更されます。

  4. すべてのコードが新しい方法を読み取ると、新しいコードは新しい方法のみを書き込むことができ、既存のコードを変更して新しい方法のみを書き込むことができます。

  5. すべてのコードが新しい方法を読み書きし、コードが古い列を参照しなくなったら、それらを削除できます。

新しい方法(日付と時刻の両方を含む1つの列)は明らかに私にとってより良いように見えます。変換プロセスを実行するのに十分な改善であるかどうかを判断する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.