web-dev-qa-db-ja.com

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

次の質問では、フィールドとテーブルの名前が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)

時間フィールドの日付コンポーネントはmostly1753年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の初期バージョンで始まったためだと言われています。日付と時刻の両方を同じ列に格納することはできませんでした。理由と方法はこの質問の一部ではありませんが、知りたい人もいます。

P.S。

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

8
oliver-clare

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

15
mjfgates

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

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

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

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

注意点:

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

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

3
Blrfl

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

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

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

2
Oleksi

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

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

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

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

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

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

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

1
JGWeissman