【问题标题】:Check if valid date in PostgreSQL source检查 PostgreSQL 源中的有效日期
【发布时间】:2015-07-30 10:45:54
【问题描述】:

我有一个无法创建自定义函数的远程 PG 数据源。我必须将 PG 数据转储到 MSSQL Server 2008 R2 上的 unicode 表中。我需要一个内联 PostgreSQL 语句,它将无效日期替换为“1900-01-01”之类的内容。

我进行了广泛的谷歌搜索,但无济于事......谢谢。

【问题讨论】:

  • 如果是日期,则不能是无效日期。
  • 我在 PG 中看到类似 '0214-06-19 00:00:00' 的内容,在插入 SQLServer 日期时间时失败并出现溢出错误。
  • '0214-06-19 00:00:00' 是一个有效的时间戳。 PostgreSQL 时间戳的覆盖范围比 SQL Server 日期时间大得多。

标签: sql-server postgresql validation date


【解决方案1】:

PostgreSQL 的时间戳范围比 SQL Server 的日期时间范围大得多。在 PostgreSQL 中,'0214-06-19 00:00:00' 是一个有效的时间戳。 '0214-06-19 00:00:00 BC'也是如此。

我不清楚结果应该是日期还是时间戳。但这显示了您应该如何解决 PostgreSQL 中的问题

with data (ts) as (
  values (timestamp '0214-06-19 00:00:00'), ('1900-01-01 08:00')
)
select 
    ts as source_ts, 
    case when ts < timestamp '1900-01-01' then timestamp '1900-01-01' 
         else ts 
    end as altered_ts
from data;
source_ts 改变的_ts -- 0214-06-19 00:00:00 1900-01-01 00:00:00 1900-01-01 08:00:00 1900-01-01 08:00:00

假设 1900 年之前的每个日期都应该是 1900-01-01 有点冒险。值 '0214-06-19' 可能是 2014-06-19 的拼写错误。

【讨论】:

    【解决方案2】:

    SQL 中更复杂的算法使用 CTE 更容易编写(和阅读):

    with 
        syntax as (
            select str, 
                str ~ '^\d{4}-\d{2}-\d{2}$' as syntax_ok,
                split_part(str, '-', 1) as syy,
                split_part(str, '-', 2) as smm,
                split_part(str, '-', 3) as sdd
            from test_date),
        toint as (
            select *,
                case when syntax_ok then syy::int else 1900 end yy,
                case when syntax_ok then smm::int else 1 end mm,
                case when syntax_ok then sdd::int else 1 end dd
            from source),
        semantics as (
            select *,
                case
                when mm in (1,3,5,7,8,10,12) then dd between 1 and 31
                when mm in (4,6,9,11) then dd between 1 and 30
                when mm = 2 then 
                    case when yy/4*4 = yy and (yy/100*100 <> yy or yy/400*400 = yy)
                    then dd between 1 and 29
                    else dd between 1 and 28 end
                else false end as valid
            from toint),
        result as (
            select str,
                case when syntax_ok and valid then str
                else '1900-01-01' end as date
            from semantics)
    select * from result
    

    第一个查询检查语法并将str 分成三个部分,第二个查询将这些部分转换为整数,第三个查询检查语义。 SQLFiddle.

    您的评论表明您不需要如此彻底的检查,但我认为可以根据您的喜好轻松自定义此查询。

    【讨论】:

      【解决方案3】:

      转换为 char,然后按照您的需要格式化

      SELECT TO_CHAR(date_time_column, 'YYYY-MM-DD') AS mssql_date_format
      FROM table_name 
      WHERE -- your condition here
      
      -- results like: 1900-01-01
      

      在这里阅读更多

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-20
        • 1970-01-01
        • 1970-01-01
        • 2017-02-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-15
        相关资源
        最近更新 更多