如何在不使用子问题的情况下从Oracle功能中提取年度或月份?
How to extract year or month,day from oracle function without using sub-query?
我觉得下面的查询不适合我,
这个函数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'
从这个函数中提取日期时,请允许我将时区从不同的 reguins 转换为本地时区)
这是不可能的,因为它不是真正的列,我最终创建了新的子查询,我最终创建了许多子查询,我想避免这种情况,因为
它使查询变得复杂并且使查询花费更长的时间,
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) 如果您的 START_TIME 真的是一个字符串,那根本不是一个好主意。使用真实的 DATE 或 TIMESTAMP 数据类型。在您看来,我会将两列替换为具有 TIMESTAMP WITH TIME ZONE 数据类型的一列。实际上,由于时区偏移,您无法按日期正确排序。
2) 使用您当前的数据,您可以简化到本地时间戳的转换,我稍后会展示。
3) 正如评论中指出的那样,EXTRACT 从 UTC 时间开始,而不是本地时间,因此我将解决方案改回 TO_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
此致,
炖阿什顿
Like Stew 我不明白你的问题。当然,正确的解决方案是为您的列使用 TIMESTAMP WITH TIME ZONE
或 TIMESTAMP WITH LOCAL TIME ZONE
数据类型。
否则你可以使用函数:
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;
或者您可以定义此类值的 VIRTUAL 列。
更新:
START_TIME
和UTC_TIME_CODE_OFFSET
是列还是函数并不重要,看这个例子:
create or replace function START_TIME AS NUMBER is
begin
return TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS');
end;
你可以select这样的功能,和column一样,没有区别。
请扩展您的论点,即“我无法提取年或月、日...因为它不是真正的列”。好像您认为的 FROM 参数必须是实际的 table 列。但事实并非如此。只要参数满足EXTRACT数据要求就可以使用。对于您的情况,请参见下文:
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
我能够从一个不真实的列中提取年、月和日,至少这个解决方案避免了我对上述情况进行子查询。
我觉得下面的查询不适合我,
这个函数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'
从这个函数中提取日期时,请允许我将时区从不同的 reguins 转换为本地时区)
这是不可能的,因为它不是真正的列,我最终创建了新的子查询,我最终创建了许多子查询,我想避免这种情况,因为
它使查询变得复杂并且使查询花费更长的时间,
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) 如果您的 START_TIME 真的是一个字符串,那根本不是一个好主意。使用真实的 DATE 或 TIMESTAMP 数据类型。在您看来,我会将两列替换为具有 TIMESTAMP WITH TIME ZONE 数据类型的一列。实际上,由于时区偏移,您无法按日期正确排序。
2) 使用您当前的数据,您可以简化到本地时间戳的转换,我稍后会展示。
3) 正如评论中指出的那样,EXTRACT 从 UTC 时间开始,而不是本地时间,因此我将解决方案改回 TO_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
此致, 炖阿什顿
Like Stew 我不明白你的问题。当然,正确的解决方案是为您的列使用 TIMESTAMP WITH TIME ZONE
或 TIMESTAMP WITH LOCAL TIME ZONE
数据类型。
否则你可以使用函数:
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;
或者您可以定义此类值的 VIRTUAL 列。
更新:
START_TIME
和UTC_TIME_CODE_OFFSET
是列还是函数并不重要,看这个例子:
create or replace function START_TIME AS NUMBER is
begin
return TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS');
end;
你可以select这样的功能,和column一样,没有区别。
请扩展您的论点,即“我无法提取年或月、日...因为它不是真正的列”。好像您认为的 FROM 参数必须是实际的 table 列。但事实并非如此。只要参数满足EXTRACT数据要求就可以使用。对于您的情况,请参见下文:
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
我能够从一个不真实的列中提取年、月和日,至少这个解决方案避免了我对上述情况进行子查询。