我应该将org.joda.time.YearMonth存储为日期还是PostgreSQL中的两列?

时间:2015-01-29 16:15:08

标签: sql postgresql date

我在我的数据模型中存储特定月份(含年份)的值。为简单起见,我们假设我会将这几个月的平均温度存储起来:

|  month  | degreeCelsius |
+---------+---------------|
| 2010-01 |     5.2       |
| 2010-02 |     6         |
| 2010-03 |     6.8       |
|   ...   |     ...       |

现在我想将这些数据保存到PostgreSQL表中,我想知道一个月使用哪种数据类型。在我的Java应用程序中,我使用org.joda.time.YearMonth类型来表示月份。

基本上我有两个想法:要么我使用date类型,它也会为" day"这将毫无意义。由于月份是表格的主键,因此在同一个月(但具有不同的日期)不会插入两个值并且我可以可靠地搜索特定年月的平均温度,这一点非常重要。因此,我可以创建一个约束,强制日必须始终是" 1"如果我想要2010年2月的价值,我可以可靠地搜索2010-02-01

然而,保持一天的感觉有点尴尬,而其他人在查看数据模型时可能会对当天的部分感到困惑。因此,另一个想法是将该类型拆分为两列:yearmonth。这是否会引入我未能看到的新问题?哪个解决方案更好" /我应该注意哪些缺点?

2 个答案:

答案 0 :(得分:2)

我建议约会,因为在sql查询中进行日期算术时可以直接使用它。

请注意,实现您提到的检查约束的一种好方法是执行value=date_trunc('month', value)。这样您就可以保证没有与该值关联的时间值。 (编辑:实际上没关系,因为postgres有一个不接受时间值的日期数据类型。我已经习惯了oracle,我们会遇到" date"数据类型实际上是时间戳)

答案 1 :(得分:0)

我不喜欢使用日期。在这种情况下,日期违反了最低惊喜原则。

所以我将数月存储为一列或两列。如果你需要做日期算术 - 这在我的经验中是不太可能的 - 你可以得到一个带连接和演员的日期或时间戳。

要注意的两个关键事项是约束和特权。

一栏

在表中存储有效月份,并设置外键引用。

create table months (
  cal_month char(7) primary key
);

insert into months 
select left(generate_series('2010-01-01'::timestamp, 
                            '2100-12-01'::timestamp, 
                            '1 month')::text, 7);

您希望从几乎所有人撤消对该表的权限。

create table avg_temps (
  cal_month char(7) primary key references months (cal_month),
  temp_c numeric(3, 1)
);

insert into avg_temps values
('2010-01', 5.2), ('2010-02', 6), ('2010-03', 6.8);

两栏

您可以将基表放在不同的架构中。 (也适用于单列解决方案。)这可以使控制权限变得更加简单。

create schema temperature;

create table temperature.avg_temps (
  cal_year integer not null
    check (cal_year between 2010 and 2100),
  cal_month integer not null
    check (cal_month between 1 and 12),
  temp_c numeric(3, 1)
);

insert into avg_temps values
(2010, 1, 5.2), (2010, 2, 6), (2010, 3, 6.8);

并使用公共架构中的视图使其看起来整洁。

create view public.avg_temps as 
select cal_year || '-' || lpad(cal_month::text, 2, '0') as cal_month, temp_c
from temperature.avg_temps;

我更喜欢自己的单列方法。