時間をデータベーステーブルに格納したいが、時間と分のみを格納する必要がある。DATETIMEだけを使用して日付の他のコンポーネントを無視できることはわかっていますが、実際に必要な情報よりも多くの情報を保存せずにこれを行うための最良の方法は何ですか?
時間をデータベーステーブルに格納したいが、時間と分のみを格納する必要がある。DATETIMEだけを使用して日付の他のコンポーネントを無視できることはわかっていますが、実際に必要な情報よりも多くの情報を保存せずにこれを行うための最良の方法は何ですか?
回答:
あなたはそれを真夜中過ぎの分数の整数として保存することができます:
例えば。
0 = 00:00
60 = 01:00
252 = 04:12
ただし、時間を再構成するためにいくつかのコードを記述する必要がありますが、それは難しいことではありません。
SQL Server 2008+を使用している場合は、TIME
データ型を検討してください。SQLTeamの記事に使用例が追加されています。
DATETIME開始DATETIME終了
代わりに、event_startやevent_endなどのラベルが付いた2つのDATETIME値を使用することをお勧めします。
時間は複雑なビジネスです
現在、世界のほとんどは、ほとんどの測定に、正しくまたは誤って、デナリーベースのメトリックシステムを採用しています。少なくともag、ml、立方センチメートルであることに同意できるため、これは全体的に良好です。少なくともほぼそうです。メートル法には多くの欠陥がありますが、少なくとも国際的には一貫して欠陥があります。
しかし、時間とともに、私たちは持っています。1秒あたり1000ミリ秒、60秒から1分、60分から1時間、半日ごとに12時間、問題の月や年によって異なる月あたり約30日、各国の時間オフセット、時刻のフォーマット方法は国によって異なります。
消化することはたくさんありますが、そのような複雑なシナリオが単純な解決策を持つことは長くも短くも不可能です。
いくつかの角はカットできますが、しない方が賢明なものもあります
ここでの一番上の答えは、深夜0時の整数分を保存することは完全に合理的に思えるかもしれないことを示唆していますが、私は難しい方法でそうすることを避けることを学びました。
2つのDATETIME値を実装する理由は、精度、解像度、フィードバックを向上させるためです。
これらはすべて、設計が望ましくない結果を生成する場合に非常に便利です。
必要以上のデータを保存していますか?
最初は必要以上に多くの情報が保存されているように見えるかもしれませんが、このヒットを受け取るのには十分な理由があります。
ほとんどの場合、この追加情報を保存することで、長期的には時間と労力を節約できます。何かがかかった時間を誰かに言われたら、いつどこでイベントが行われたかも知りたいと思うからです。
巨大な惑星です
過去に、私はこの惑星に自分の国以外に他の国があることを無視することに罪を犯してきました。当時はそれは良い考えのように思われましたが、これは常に問題を引き起こし、頭痛の種となり、後の段階で時間の無駄になっています。常にすべてのタイムゾーンを考慮します。
C#
DateTimeは、C#の文字列に適切にレンダリングされます。ToString(string Format)メソッドはコンパクトで読みやすいです。
例えば
new TimeSpan(EventStart.Ticks - EventEnd.Ticks).ToString("h'h 'm'm 's's'")
SQLサーバー
また、アプリケーションインターフェイスとは別にデータベースを読み取っている場合、dateTimesは一目で読み取ることができ、計算を簡単に実行できます。
例えば
SELECT DATEDIFF(MINUTE, event_start, event_end)
ISO8601日付標準
SQLiteを使用している場合はこれがないため、代わりにテキストフィールドを使用してISO8601形式で保存します。
「2013-01-27T12:30:00 + 0000」
ノート:
これは24時間時計を使用します*
ISO8601の時間オフセット(または+0000)の部分は、GPS座標の経度値に直接マップされます(夏時間または国全体を考慮していません)。
例えば
TimeOffset=(±Longitude.24)/360
...±は東または西の方向を指します。
したがって、データとともに経度、緯度、高度を保存する価値があるかどうかを検討する価値があります。これはアプリケーションによって異なります。
ISO8601は国際的なフォーマットです。
wikiは、http://en.wikipedia.org/wiki/ISO_8601で詳細を調べるのに非常に適しています。
日付と時刻は国際時で保存され、オフセットは世界のどこに保存されたかによって記録されます。
私の経験では、プロジェクトの開始時に存在するかどうかに関係なく、常に完全な日付と時刻を保存する必要があります。ISO8601は、非常に優れた、将来性のある方法です。
無料の追加アドバイス
イベントをチェーンのようにグループ化することも価値があります。たとえば、レースを記録する場合、イベント全体をレーサー、race_circuit、circuit_checkpoints、circuit_lapsでグループ化できます。
私の経験では、誰がレコードを保存したかを特定することも賢明です。トリガーを介して入力される別のテーブルとして、または元のテーブル内の追加の列として。
入れれば置くほど、外に出ます
スペースをできるだけ節約したいという願望は完全に理解していますが、情報を失うという犠牲を払ってそうすることはめったにありません。
データベースの経験則は、タイトルが示すように、データベースはデータがある場合にのみ通知することができ、ギャップを埋めて履歴データをさかのぼることは非常にコストがかかる可能性があります。
解決策は、最初にそれを正しくすることです。これは言うより言うのは確かに簡単ですが、効果的なデータベース設計についての深い洞察を得て、その後、初めて正しく機能する可能性が大幅に向上するはずです。
初期設計が良ければ、後で修理する費用も少なくて済みます。
私がこれだけを言うのは、もし私が時間を遡ることができたなら、そこに着いたときにそれを私は自分に言い聞かせるものだからです。
通常の日時を保存し、その他はすべて無視してください。日時のみをロードできるのに、intをロードして操作し、それを日時に変換するコードを書くのに余分な時間を費やすのはなぜですか?
DATETIME
データタイプは4バイトを格納SMALLINT
しますが、たとえば、データタイプはその4 分の1しかかかりません。行が数千行しかない場合は大きな違いはありませんが、多くの企業と同様に数百万行がある場合は、スペースを大幅に節約できます。
SQL Serverは実際には時間を1日の端数として格納します。たとえば、1日は1の値です。12時間は0.5の値です。
DATETIME型を使用せずに時刻の値を格納する場合は、10進数形式で時刻を格納すると、そのニーズに合うだけでなく、DATETIMEへの変換も簡単になります。
例えば:
SELECT CAST(0.5 AS DATETIME)
--1900-01-01 12:00:00.000
値をDECIMAL(9,9)として格納すると、5バイトが消費されます。ただし、精度があまり重要でない場合、REALは4バイトしか消費しません。どちらの場合でも、集計計算(平均時間)は数値で簡単に計算できますが、データ/時間型では計算できません。
私はそれらを整数(HH * 3600 + MM * 60)に変換し、そのように格納します。小さいストレージサイズでありながら、操作するのに十分簡単です。
minutes-past-midnightの代わりに、SMALLINTとして24時間時計として保存します。
09:12 = 912 14:15 = 1415
「人間が読める形式」に戻すときは、右から2文字コロン「:」を挿入するだけです。必要に応じて、左側にゼロを埋め込みます。数学をそれぞれの方法で保存し、(varcharと比較して)使用するバイト数を減らし、値を(英数字ではなく)数値にすることを強制します。
かなり間抜けですが... MS SQLにはTIMEデータ型が何年も前から存在しているはずですIMHO ...
あなたが求めているのは、分を数値として格納する変数です。これは、さまざまなタイプの整変数を使用して行うことができます。
SELECT 9823754987598 AS MinutesInput
次に、プログラムでこれを計算することで、希望する形式でこれを表示できます。
long MinutesInAnHour = 60;
long MinutesInADay = MinutesInAnHour * 24;
long MinutesInAWeek = MinutesInADay * 7;
long MinutesCalc = long.Parse(rdr["MinutesInput"].toString()); //BigInt converts to long. rdr is an SqlDataReader.
long Weeks = MinutesCalc / MinutesInAWeek;
MinutesCalc -= Weeks * MinutesInAWeek;
long Days = MinutesCalc / MinutesInADay;
MinutesCalc -= Days * MinutesInADay;
long Hours = MinutesCalc / MinutesInAnHour;
MinutesCalc -= Hours * MinutesInAnHour;
long Minutes = MinutesCalc;
使用する効率を要求する問題が発生します。ただし、時間が足りない場合は、null許容のBigIntを使用して分の値を格納します。
nullの値は、時刻がまだ記録されていないことを意味します。
さて、宇宙への往復という形で説明します。
残念ながら、テーブルの列には1つの型のみが格納されます。したがって、必要に応じて、タイプごとに新しいテーブルを作成する必要があります。
例えば:
MinutesInput = 0 .. 255の場合、TinyInt(上記のように変換)を使用します。
MinutesInput = 256 .. 131071の場合は、SmallInt を使用します(注:SmallIntのmin値は-32,768です。したがって、値を格納および取得する場合は、32768を否定して追加し、上記のように変換する前に全範囲を利用します)。
MinutesInput = 131072 .. 8589934591の場合は、Intを使用します(注:否定し、必要に応じて2147483648を追加します)。
MinutesInput =場合は8589934592 ... 36893488147419103231は、その後、使用のBigInt (:必要に応じて追加し、否定9223372036854775808注)。
MinutesInput> 36893488147419103231の場合、charはバイトなので、必要に応じてVARCHAR(X)を使用してXを増やします。私はこれを完全に説明するために後日この回答を再訪する必要があります(または、仲間のstackoverfloweeがこの回答を終了できるかもしれません)。
間違いなく各値には一意のキーが必要であるため、データベースの効率は、格納された値の範囲が非常に小さい(0分に近い)と非常に高い(8589934591より大きい)の間の適切な組み合わせである場合にのみ明らかになります。
保存されている値が実際に36893488147419103231より大きい数値に達するまでは、分を表すために単一のBigInt列を使用することもできます。これは、一意の識別子のIntと分値を保存する別のintを無駄にする必要がないためです。
保管ticks
とlong
/ bigint
現在のミリ秒単位で測定されています、。更新された値は、TimeSpan.TicksPerSecond
値を見ることで見つけることができます。
ほとんどのデータベースには、時間の背後にあるティックとして時間を自動的に格納するDateTimeタイプがありますが、SqlLiteなどの一部のデータベースの場合、ティックを格納することで日付を格納できます。
ほとんどの言語は、より簡単に変換できるようTicks
→ TimeSpan
→をTicks
。
例
C#では、コードは次のようになります。
long TimeAsTicks = TimeAsTimeSpan.Ticks;
TimeAsTimeSpan = TimeSpan.FromTicks(TimeAsTicks);
ただし、SqlLiteの場合、少数の異なるタイプしか提供しないため、注意してください。INT
、REAL
そしてVARCHAR
ティック数を文字列または2つのINT
セルを組み合わせて保存する必要があります。これは、64 INT
ビットの符号付き数値であるのに対し、32ビットの符号付き数値BIGINT
だからです。
注意
しかし、私の個人的な好みは、日付と時刻をISO8601
文字列として保存することです。
最良のソリューションが何であるかは、残りのデータベース(およびアプリケーションの残りの部分)に時間を格納する方法にある程度依存します
個人的に私はSQLiteを使用して絶対時間を保存するために常にUNIXタイムスタンプを使用するように努めているので、時刻を処理するとき(あなたが求めるように)、Glen Solsberryが彼の回答に書いたことを行い、真夜中からの秒数を保存します
この一般的なアプローチを採用する場合、どこにでも同じ標準を使用すると、人々(私を含む)がコードを読むのが混乱しにくくなります。