Postgres转换数据类型

时间:2016-03-31 11:31:35

标签: postgresql sqldatatypes

我有一个列保存为字符数据类型。本专栏将作为日期使用。该列以该格式显示“YYYY-MM-DD”。

这是一个问题,因为如果我需要按日期过滤,我必须去

select col_1, col_2
from table
where date LIKE '2016-04%;

如果我想搜索日期范围,这会变成一个巨大的复杂混乱。

将此转换为“日期”数据类型的最简单方法是什么?我希望它继续以YYYY-MM-DD顺序(没有时间戳)。

我的最终目标是能够以这样的格式搜索日期:

select col_1, col_2
from table
where date between 2016-01-01 AND 2016-05-31;

你们推荐什么?我很害怕如果我使用alter语句来转换我的数据类型,我将破坏我的约会。 (我有一份保存的数据副本,可以再次上传,但需要永久上传。)

编辑:这是一个非常大的表。

编辑第2部分:我最初将数据存储为varchar数据类型,因为我的日期没有正确上传,当我尝试保存为日期数据类型时收到错误消息。此列中的每个日期都是“YYYY-MM-DD”顺序。我的解决方案是将其保存为varchar以避免错误消息(我无法弄清楚出了什么问题。我甚至摆脱了前导和尾随空格。)

3 个答案:

答案 0 :(得分:5)

将日期存储为varchar是错误的选择。你想要改变它是非常好的。

第一步是使用ALTER TABLE语句转换列:

alter table the_table
   ALTER COLUMN col_1 TYPE date using col_1::date, 
   ALTER COLUMN col_2 TYPE date using col_2::date;

请注意,如果这些列中的任何值无法转换为正确的日期,则会失败。如果你得到了,你需要先修复这些无效字符串,然后才能更改数据类型。

  

我希望它继续以YYYY-MM-DD顺序

这是一种误解。 DATE(或timestamp)没有“格式”。一旦将其存储为日期,您就可以以任何您想要的格式显示它。

  

我的最终目标是能够以这样的格式搜索日期:

2016-01-01不是有效的日期文字,可以指定适当的(即正确输入的)日期常量,例如使用date '2016-01-01'(注意单引号!

所以你的查询变为:

select col_1, col_2
from table
where col_1 between date '2016-01-01' AND date '2016-05-31';

如果你有很多这样的查询,你应该考虑在日期列上创建一个索引。

关于日期常量格式:

  

你是否告诉我,尽管有varchar数据类型,我仍然可以(截至目前)在特定日期之间搜索,只需输入单词date并在两个日期之间放置单引号

不,事实并非如此。 SQL是一种强类型语言,因此只会比较相同类型的值。

使用ANSI日期文字(或例如to_date())会产生类型常量(即具有特定数据类型的值)。

date '2016-01-01' and '2016-01-01' is the same as between 42 (a number) and'42'`(一个字符串)之间的差异。

如果将字符串与日期进行比较,则表示您正在比较苹果和橙子,并且数据库将执行从一种类型到另一种类型的隐式数据类型转换。应该不惜一切代价避免这种情况。

如果您不想更改表,则应使用提供的查询sagi,它将字符串显式转换为日期,然后对(实际)日期值(而不是字符串)进行比较

答案 1 :(得分:1)

您可以使用POSTGRES TO_DATE()强制转换功能:

SELECT col_1,col_2
FROM Your_Table
WHERE to_date(date_col,'yyyy-mm-dd') between to_date('2016-05-31','yyyy-mm-dd') and to_date('2016-01-01','yyyy-mm-dd')

答案 2 :(得分:0)

What @a_horse said.

Plus ,如果由于某些奇怪的原因无法更改数据类型,to_date()是转换列上列的安全选项,但没有必要使用提供常量的相同表达式。所以:

SELECT col_1, col_2
FROM   tbl
WHERE  to_date(date, 'YYYY-DD-MM') BETWEEN date '2016-05-31' AND date '2016-01-01';

或者只使用没有类型的字符串文字。类型date从此表达式中的上下文推迟。你甚至不需要to_date()。由于您已经使用ISO格式。普通演员是安全的:

WHERE date::date BETWEEN '2016-05-31' AND '2016-01-01';

请务必对所有日期字符串使用ISO 8601格式,因此它们对任何语言环境都是明确无误的。

您甚至可以使用表达式索引来支持查询。匹配查询中使用的实际表达式:

CREATE INDEX tbl_date_idx ON tbl ((date::date));  -- parentheses required!

但我不会使用基本类型名称date作为标识符开始。