【问题标题】:Postgres Converting Data TypesPostgres 转换数据类型
【发布时间】:2016-07-19 20:03:53
【问题描述】:

我有一列保存为字符数据类型。本专栏将用作日期。该列采用该格式“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 以避免错误消息(我无法弄清楚出了什么问题。我什至摆脱了前导和尾随空格。)

【问题讨论】:

  • 因为我的日期没有正确上传,当我尝试保存为日期数据类型时收到一条错误消息”,这应该是一个公平的警告开始。使用正确数据类型的一个原因是避免存储无效数据(例如 2016-16-00 或 2015-02-29)
  • 没有一个日期有这样奇怪的格式,我唯一的猜测是后面有空格。
  • 前导或尾随空格不会阻止转换为日期。 select ' 2016-01-01 '::date 工作得很好

标签: postgresql sqldatatypes


【解决方案1】:

你可以使用POSTGRESTO_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】:

    将日期存储为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 并在两个日期之间加上单引号来搜索特定日期 p>

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

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

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

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

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

    【讨论】:

    • 1) 如果由于我的“YYYY-MM-DD”订单而在尝试更改表格时确实收到错误消息,您会如何建议我更改订单以实现它工作吗?
    • 2) 您是否告诉我,尽管有 varchar 数据类型,但我仍然可以(截至目前)通过键入单词 date 并在两个日期之间加上单引号来搜索特定日期?我不必在表上使用 alter table 语句(最坏的情况),而且,我肯定计划在日期列上使用索引。
    • @LunchBox: 1) 查找日期无效的行,例如通过使用正则表达式然后更改这些值。
    • 当我更改值时,是否有特定的方法可以更改值? IE。去改变列,使值看起来像这样'YYYYMMDD'?
    • 请注意,如果列中有无效值,to_date(date_col,'yyyy-mm-dd') 也会失败。
    【解决方案3】:

    What @a_horse said.

    另外,如果由于某种奇怪的原因不能更改数据类型,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 作为开头的标识符。

    【讨论】:

      猜你喜欢
      • 2012-11-20
      • 1970-01-01
      • 2018-05-14
      • 2018-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多