相同的数据类型,不同的数据行为

时间:2019-04-12 15:05:52

标签: sql database oracle

我的一个表中有一列,数据类型为TIMESTAMP(6) WITH TIME ZONE。但是,此列中的数据显示方式不同,例如:

某些记录显示诸如02-NOV-17 02.26.22.000000000 PM -04:00

之类的数据

和其他一些数据显示数据,例如19-APR-18 10.31.15.000000000 PM AMERICA/NEW_YORK

为什么会这样?还有一个SQL查询,我可以用来检查表中的其他地方是否正在发生(如果它发生在其他地方)。

1 个答案:

答案 0 :(得分:1)

From the documentation

  

TIMESTAMP WITH TIME ZONETIMESTAMP的一种变体,在其值中包含时区区域名称或时区偏移。

表中的值包含区域和偏移量。您的客户将显示所有带有其“区域”的值,但只有在其实际具有一个值的情况下,它才可以这样做。如果它有一个偏移量,则会显示出来。

输入了各种值的演示,包括会话时区的隐式转换:

alter session set time_zone = 'Europe/London';

create table t42 (test timestamp(6) with time zone);
insert into t42 (test) values (timestamp '2018-11-02 14:26:22.0 -04:00');
insert into t42 (test) values (timestamp '2018-04-19 22:31:15.0 America/New_York');
insert into t42 (test) values (systimestamp);
insert into t42 (test) values (sysdate);
insert into t42 (test) values (current_timestamp);
insert into t42 (test) values (current_date);

alter session set time_zone = 'America/New_York';

insert into t42 (test) values (systimestamp);
insert into t42 (test) values (sysdate);
insert into t42 (test) values (current_timestamp);
insert into t42 (test) values (current_date);

如果您使用sysdate,它将使用您的会话时区(可能是区域或偏移量)进行隐式转换。如果您使用systimestamp,它将保留时区信息,通常是(如果不是总是)偏移量而不是区域,它是来自服务器操作系统。

然后使用区域格式为TZR的格式模型进行查询:

alter session set nls_timestamp_tz_format = 'SYYYY-MM-DD HH24:MI:SS.FF3 TZR';

select * from t42;

TEST                                              
--------------------------------------------------
 2018-11-02 14:26:22.000 -04:00
 2018-04-19 22:31:15.000 AMERICA/NEW_YORK
 2019-04-12 16:36:30.441 +01:00
 2019-04-12 16:36:30.000 EUROPE/LONDON
 2019-04-12 16:36:30.622 EUROPE/LONDON
 2019-04-12 16:36:30.000 EUROPE/LONDON
 2019-04-12 16:36:30.862 +01:00
 2019-04-12 16:36:30.000 AMERICA/NEW_YORK
 2019-04-12 11:36:31.052 AMERICA/NEW_YORK
 2019-04-12 11:36:31.000 AMERICA/NEW_YORK

您可以使用TZD:TZH而不是TZR来一致地显示所有带有偏移的内容。

alter session set nls_timestamp_tz_format = 'SYYYY-MM-DD HH24:MI:SS.FF3 TZH:TZM';

select * from t42;

TEST                                              
--------------------------------------------------
 2018-11-02 14:26:22.000 -04:00
 2018-04-19 22:31:15.000 -04:00
 2019-04-12 16:36:30.441 +01:00
 2019-04-12 16:36:30.000 +01:00
 2019-04-12 16:36:30.622 +01:00
 2019-04-12 16:36:30.000 +01:00
 2019-04-12 16:36:30.862 +01:00
 2019-04-12 16:36:30.000 -04:00
 2019-04-12 11:36:31.052 -04:00
 2019-04-12 11:36:31.000 -04:00

但是您不能仅从偏移量推断区域,因为它们不是唯一的。

  

我想知道是否可以运行查询以获取所有包含区域和偏移量的表?

不是简单的查询;可以使用XML技巧来实现,但是我似乎正在遇到一个错误,因此,在我弄清楚这一点之前,您可以使用运行动态SQL的匿名块来做到这一点:

set serveroutput on -- or equivalent for your client

declare
  l_table_name user_tab_columns.table_name%type;
  l_column_name user_tab_columns.column_name%type;
begin
  for r in (
      select 'select ''' || table_name || ''', ''' || column_name || ''''
          || ' from dual '
          || ' where exists (select * from "' || table_name || '" where extract(timezone_region from "' || column_name || '") = ''UNKNOWN'')'
          || ' and exists (select * from "' || table_name || '" where extract(timezone_region from "' || column_name || '") != ''UNKNOWN'')'
          as query
      from user_tab_columns
      where data_type like 'TIMESTAMP(_) WITH TIME ZONE'
  )
  loop
    begin
      execute immediate r.query into l_table_name, l_column_name;
      dbms_output.put_line('Both TZR and TZH:TZM in table ' || l_table_name || '.' || l_column_name);
    exception
      when no_data_found then
        null;
    end;
  end loop;
end;
/

这两个exists()子句查找具有时区值的,具有偏移量的任何时间戳记-由extract()报告为'UNKNOWN'-并具有一个区域,以及由游标生成的动态查询仅在同时满足两个条件(即,同时具有两种类型)的情况下,才为表/列查找虚拟对象。因此,在循环内需要异常处理程序。如果您实际上想查找任何带有偏移量的存储,则只需省略第二个exists()子句。