2017-03-28 13 views
0

データベースに保存する日付を収集していますが、ユーザーが正確な日付を知らないという事実を考慮する必要があります。私は月と年だけを入力するオプションを提供したいと思います。これらの値をデータベースに保存する最良の方法は何でしょうか?Rails - 日がオプションの日付を格納する

Dateオブジェクトを曜日なしで使用し、日付としてデータベースに格納すると、デフォルトは月の1日になりますが、これは不正確になります。私は日、月、年を別々に整数として格納し、Dateオブジェクトを返すモデルのメソッドと、その日が正確であったかどうかを考えていました(つまり、ユーザーによって入力され、システム)。

少し面倒ですが、これを行うには良い方法がありますか?

ありがとうございました。

+0

あなたは、1列およびその他の精度、例えば「2017年3月28日」、「日」と「2017年3月1日」、「月」に日付を保存することができます正確な日付から "2017-03-01"、 "day" –

答えて

1

利用可能な複数のソリューションがあります。あなたは既にこのアイデアを試してきました

1.個々の日付の部分のフィールド

:あなたのユースケース最高を提供していますいずれかを選択します。

create table t(
    year int, 
    month int, 
    day int 
) 

2017-03の月(2017, 3, NULL)で表すことができる:このような何かがいるようです。

すべてのフィールドはNULL - 可能です。何か情報が必要な場合はyear NOT NULLにすることができます。

このモデルでは、後で使用するためにクライアントロジックを使用して、ある種の日付のようなオブジェクトを作成する必要があります。

このモデルの大きな欠点は、インデックス作成が難しいことです。 f.exを索引付けすることができます。 make_date(year, coalesce(month, 1), coalesce(day, 1))ですが、クエリでそれを使用するのはむしろ不便です。また、意味を持たない(f.ex。1年と1日は与えられていますが1ヶ月ではありません)値の合成を禁止するには、(実際に長い)CHECK制約も追加する必要があります。

CHECK (CASE 
    WHEN year IS NULL THEN month IS NULL AND day IS NULL 
    ELSE CASE WHEN month IS NULL THEN day IS NULL END 
END) 

2.サンプルの日付と精度

create table t(
    sample_date  date, 
    sample_precision date_precision -- enum of f.ex. 'year', 'month', 'day' 
) 

2017-03の月は('2017-03-28', 'month')で表すことができます。

これは長いCHECK制約を必要としませんが、sample_dateは本当にただのサンプル(2017-03の全体の月は行で表現されなければならないf.ex.、サンプルの日付である場合には、日付で選択するのはかなり難しいですさらに2017-03-28でもよい)。最初の日付をsample_date(それが取ることができる値から、sample_precisionに基づいて)として使用すると、少し簡単になります。しかし、その後、次のCHECK制約が整合性のために必要とされるであろう:(。後で、この更なる改善にもっと)

CHECK (date_trunc(sample_precision::text, sample_date)::date = sample_date) 

3.可能な範囲

あなたはの可能な範囲を保存することができます日付。 possible_startpossible_endまたはPostgreSQLのdaterange typeを使用してください。

create table t(
    possible_start date, 
    possible_end date, 
    -- or 
    possible_range daterange 
) 

2017-03の月は('2017-03-01', '2017-03-31')で表すことができます。

possible_start = possible_endの場合、dateの値は正確です。 (と交差する)の周りに起こった行は確かに日付(複数可)を指定した

  • が含まれています)
  • 行はおそらく日付(S)与えられたの周りが起こって:あなたは今二つの異なるものを照会することができ

両方のタイプのクエリでは、daterangeのインデックスを使用できます。

これの美しさは、あなたが月の範囲に限定されていないということです。文字通り任意の長さの範囲を使用できます。その唯一の欠点は、範囲が連続していなければならないということです。

2. + 3.?

あり3.の利点のすべてを持っている変種は、ですが、interval type2.のようになります。

create table t(
    possible_start date, 
    possible_length interval day 
) 

2017-03の月は('2017-03-01', '1 month')で表すことができます。

day修飾子がintervalの最小精度は日に制限します。これはtimestamp又はtimestamptzベースのソリューションのために必要とされない。)

(possible_start + possible_length - interval '1 day')::dateで表すことができ、最後の可能な日付。または、範囲全体(daterangeインデックスの場合):daterange(possible_start, (possible_start + possible_length)::date)(範囲は暗黙的にその終わりに排他的です)。あなたは明確な希望よう

http://rextester.com/AWIO2403

+0

の前にdate_truncに出くわしたわけではありません包括的な回答をいただきありがとうございます。 。私は日付を索引付けする必要はないので、唯一の日が欠けている可能性があるので、最初のオプションを使用して値を別々に保管します。再度、感謝します! –

1

あなたは例えば、あなたがdate_trunc(precision_column,DATE)を使用することができ、値を比較するために、他に1列と精度で日付を保存することができます:

t=# create table so36(d date,p text); 
CREATE TABLE 
t=# insert into so36 select now(),'day'; 
INSERT 0 1 
t=# insert into so36 select '2017-03-01','month'; 
INSERT 0 1 
t=# select *,date_trunc(p,d),date_trunc(p,now()) from so36; 
    d  | p |  date_trunc  |  date_trunc 
------------+-------+------------------------+------------------------ 
2017-03-28 | day | 2017-03-28 00:00:00+00 | 2017-03-28 00:00:00+00 
2017-03-01 | month | 2017-03-01 00:00:00+00 | 2017-03-01 00:00:00+00 
(2 rows) 
+0

このソリューションを提供してくれてありがとうございました –

関連する問題