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

问题描述 投票:0回答:1

我的一个表中有一个列,其数据类型为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查询,我可以用它来检查我的表中发生的其他地方(如果它发生在其他地方)。

sql database oracle
1个回答
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技巧,但我似乎遇到了一个bug,所以在我弄明白之前,你可以使用运行动态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()子句。

© www.soinside.com 2019 - 2024. All rights reserved.