Sql 如何在不使用子查询的情况下从oracle函数中提取年或月、日?

Sql 如何在不使用子查询的情况下从oracle函数中提取年或月、日?,sql,database,oracle,plsql,timestamp-with-timezone,Sql,Database,Oracle,Plsql,Timestamp With Timezone,我知道下面的问题对我不起作用 此函数从\u tz(到\u时间戳(开始时间,'yyyyymmddhh24miss'), substr(UTC|U时间|U代码|U偏移量,1,3)| |':“| |'00')在本地作为本地|tstz 当我尝试使用to_CHAR(from_tz(to_timestamp)(START_TIME,'YYYYMMDDHH24MISS')从该函数提取日期时,请允许我将时区从Different reguins转换为local, substr(UTC|U时间|U代码|U偏移量,1

我知道下面的问题对我不起作用

此函数
从\u tz(到\u时间戳(开始时间,'yyyyymmddhh24miss'),
substr(UTC|U时间|U代码|U偏移量,1,3)| |':“| |'00')在本地作为本地|tstz
当我尝试使用
to_CHAR(from_tz(to_timestamp)(START_TIME,'YYYYMMDDHH24MISS')从该函数提取日期时,请允许我将时区从Different reguins转换为local,
substr(UTC|U时间|U代码|U偏移量,1,3)| |':“| |'00')在本地作为本地|tstz,'DD'这是不可能的,因为它不是一个真正的列,我最终创建了新的子查询,我最终创建了许多子查询,我想避免这样做,因为
它使查询变得复杂,并且使查询花费的时间更长

select from_tz(to_timestamp(START_TIME, 'YYYYMMDDHH24MISS'), 
substr(UTC_TIME_CODE_OFFSET,1,3)||':'||'00'),
from_tz(to_timestamp(START_TIME, 'YYYYMMDDHH24MISS'), 
substr(UTC_TIME_CODE_OFFSET,1,3)||':'||'00') at local as local_tstz,
to_char(from_tz(to_timestamp(START_TIME, 'YYYYMMDDHH24MISS'), 
substr(UTC_TIME_CODE_OFFSET,1,3)||':'||'00') at local as local_tstz,'DD')
from TAPIN_201906@billingdb;

我无法在19c版中重现您的问题,否则我不理解。无论如何,有三点意见:

1) 如果你的开始时间真的是一个字符串,那根本不是一个好主意。使用实际日期或时间戳数据类型。在您看来,我将用时区数据类型的时间戳将两列替换为一列。实际上,由于时区偏移,您无法按日期正确排序

2) 使用当前数据,您可以简化到本地时间戳的转换,我将在一分钟后介绍

3) 正如在一篇评论中指出的,提取从UTC时间开始,而不是本地时间,所以我将解决方案改回了_CHAR

with data(START_TIME, UTC_TIME_CODE_OFFSET) as (
  select '20001112012345', '+02' from dual
)
select
to_timestamp_TZ(
  START_TIME || substr(UTC_TIME_CODE_OFFSET,1,3),
  'YYYYMMDDHH24MISSTZH'
)  at local as local_ts,
to_char(
  to_timestamp_TZ(
    START_TIME || substr(UTC_TIME_CODE_OFFSET,1,3),
    'YYYYMMDDHH24MISSTZH'
  )
  ,'DD'
) as to_char_day,
extract(
  day from
  to_timestamp_TZ(
    START_TIME || substr(UTC_TIME_CODE_OFFSET,1,3),
    'YYYYMMDDHH24MISSTZH'
  )
) as extract_day
from data;

LOCAL_TS                                   TO_CHAR_DAY EXTRACT_DAY   
2000-11-12 00:23:45,000000000 EUROPE/PARIS 12          11
致以最良好的祝愿,
像炖肉一样炖阿什顿我不明白你的问题。当然,正确的解决方案是为列使用带时区的
时间戳
或带本地时区的
时间戳
数据类型

否则,您可以使用以下函数:

create or replace function TO_LOCAL(START_TIME IN DATE, UTC_TIME_CODE_OFFSET IN integer) return TIMESTAMP WITH TIME ZONE as
begin
    RETURN from_tz(to_timestamp(START_TIME, 'YYYYMMDDHH24MISS'), 
UTC_TIME_CODE_OFFSET||':'||'00') at local;
end TO_LOCAL;
也可以定义此类值的虚拟列

更新:

无论
START\u TIME
UTC\u TIME\u code\u OFFSET
是列还是函数,请参见此示例:

create or replace function START_TIME AS NUMBER is
begin
    return TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS');
end;

您可以用与列相同的方式选择此函数,没有区别。

请详细说明您的论点,即“我无法提取年或月、日…”。。。因为它不是一个真正的专栏。似乎您认为的FROM参数必须是实际的表列。但事实并非如此。只要参数满足提取数据要求,就可以使用。有关您的案例,请参见以下内容:

alter session set NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
declare 
     UTC_TIME_CODE_OFFSET varchar2(3) := '-05';
     start_date           varchar2(14);

     function get_some_date 
       return  varchar
     as 
     begin 
         return to_char(sysdate + dbms_random.value(1000,10000), 'YYYYMMDDHH24MISS')  ;
    end get_some_date;    

begin
   for i in 1 .. 10
   loop 
       start_date := get_some_date; 
       dbms_output.put( 'Date is ' || to_date(start_date, 'yyyy-mm-dd hh24:mi:ss'));   
       dbms_output.put( ' Extract month is ' ||  EXTRACT( month FROM (from_tz(to_timestamp( start_date, 'YYYYMMDDHH24MISS'), substr(UTC_TIME_CODE_OFFSET,1,3)||':'||'00'))) );
       dbms_output.put( ' Extract year is '  ||  EXTRACT( year  FROM (from_tz(to_timestamp( start_date, 'YYYYMMDDHH24MISS'), substr(UTC_TIME_CODE_OFFSET,1,3)||':'||'00'))) );
       dbms_output.put( ' Extract day is '   ||  EXTRACT( day   FROM (from_tz(to_timestamp( start_date, 'YYYYMMDDHH24MISS'), substr(UTC_TIME_CODE_OFFSET,1,3)||':'||'00'))) );
       dbms_output.put_line('.');
   end loop;
end ;

请注意EXTRACT函数的FROM参数周围的括号

我使用下面的代码为我的案例找到了解决方案

 to_char(from_tz(to_timestamp(START_TIME, 'YYYYMMDDHH24MISS'), 
 substr(UTC_TIME_CODE_OFFSET,1,3)||':'||'00') at local,'yyyymmdd') as local_tstz

我能够从一个不真实的列中提取年、月和日,至少这个解决方案避免了我对上述情况进行子查询。

使用子查询或CTE。时区与UTC的距离并不总是全小时,例如伊朗的UTC+04:30或印度的UTC+05:30。您可能需要在代码中考虑这一点。亲爱的WnnFrReDeMeSoeTIT,我对时区没有问题,问题是时区的列不是实列,它从函数<代码>中得到值(ToTimeTimes(StaskTime',YyYYMDDHH24Mess)),SUBR(UTCKTIMEL CODEL偏移,1,3)′′:'`'′'00)在本地作为本地\u tstz
,因此您不能使用
来\u CHAR
提取(正常情况下从
开始的一天。问题出在哪里?无论
START\u TIME
UTC\u TIME\u code\u OFFSET
是列还是函数。
START\u TIME
UTC\u TIME\u code\u OFFSET
都是真正的列。请注意,在带有{LOCAL}的
时间戳上使用
EXTRACT()
时区
值然后结果指UTC时间。Wernfried,我不知道!谢谢你指出这一点。我将我的答案改为使用_CHAR。我的问题是,我无法使用
to _CHAR从oracle
中的这个函数提取年或月、日值到_CHAR(从_tz(到_timestamp)(开始时间,'yyyymmddh24 miss')),substr(UTC_TIME_CODE_OFFSET,1,3)| |’:“| | |'00')在本地作为本地作为本地的(tstz,'DD')因为它不是一个真正的列,我会尝试你的解决方案谢谢=)另一个选项是提取(日期从(在本地转换为(到_timestamp)TZ(…)作为时间戳))Osama?这是一个表达式,你可以在这些函数中使用表达式。你收到错误消息了吗?错误消息到底是什么?你能告诉我们如何复制它吗?你的Oracle版本是什么?我的问题是,我不能使用
to_CHAR
从Oracle
to_tz(to_timestamp)中的这个函数提取年或月、日值(开始时间,'YYYYMMDDHH24MISS'),substr(UTC时间代码偏移量,1,3)| |':'| | |'00'),因为它不是一个实际的列。