Использование функции Oracle «в часовом поясе» в SQL - проблема и решение - PullRequest
1 голос
/ 11 ноября 2010

У меня есть таблица со столбцом даты, который, как я знаю, хранится в GMT. У меня есть процедура, которая принимает ввод даты и идентификатор учетной записи. Процедура: 1) получает идентификатор аккаунта часового пояса (хранится в таблице аккаунта) 2) определяет начальный и конечный диапазон в GMT следующим образом: v_start_time: = cast (from_tz (cast (i_date как отметка времени), v_tz) в часовом поясе c_gmt как дата); - где вводится i_date, v_tz - это «US / Eastern» или любое другое tzname из v $ timezone_names, а c_gmt - это строка «GMT» v_end_time: = v_start_time + 1; - Добавить ровно один день до даты начала 3) вернуть sys_refcursor вызывающей стороне как:

open o_cur for
select gmt_col, some_value
from my_table
where account_id = i_account_id
    and gmt_col between v_start_time and v_end_time;

Однако разработчик хотел бы указывать и gmt_date, и местное время в курсоре. Сначала я попытался использовать точно такой же метод преобразования, как и для определения v_start_time, то есть:

open o_cur for 
select gmt_col,
    cast( from_tz( cast( gmt_col as timestamp ), c_gmt ) at time zone v_tz as date ) as local_time, some_value
from my_table
where account_id = i_account_id
    and gmt_col between v_start_time and v_end_time;

Однако при компиляции это приводит к ORA-00905: отсутствует ключевое слово. Я попытался добавить одинарные кавычки вокруг "v_tz", например: chr (39) || v_tz || chr (39), но это не работает - процесс компилируется, но когда я открываю курсор, я получаю ORA-01882: область часового пояса не найдена. После небольшого количества экспериментов вот два решения, которые позволяют "в часовом поясе" работать гладко в sql:

РЕШЕНИЕ 1:

open o_cur for
select gmt_col,
    cast( from_tz( cast( gmt_col as timestamp ), c_gmt ) at time zone ( select v_tz from dual ) as date ) as local_time, some_value
from my_table
where account_id = i_account_id
    and gmt_col between v_start_time and v_end_time;

РЕШЕНИЕ 2:

в спецификации пакета:

function echo( i_sound in varchar2 ) return varchar2;
pragma restrict_references( echo, wnps, rnps, wnds, rnds );

в упаковке:

function echo( i_sound in varchar2 ) return varchar2 is begin return i_sound; end;

в процедуре:

open o_cur for
select gmt_col,
    cast( from_tz( cast( gmt_col as timestamp ), c_gmt ) at time zone echo( v_tz ) as date ) as local_time, some_value
from my_table
where account_id = i_account_id
   and gmt_col between v_start_time and v_end_time;

Производительность представляется сопоставимой для каждого. Второе решение намекает на то, что я начал делать недавно, а именно на использование функций для возврата «констант» с прагмой restrict_references, поэтому я могу гибко использовать константы между pl ​​/ sql и sql. Например:

function c_gmt return varchar2; прагма restrict_references (c_gmt, wnds, rnds, wnps, rnps);

выберите * из v $ timezone_names, где tzabbrev = c_gmt; выберите c_gmt из двойного; v_start_time: = бла-бла-бла || c_gmt; и т.д ...

1 Ответ

4 голосов
/ 11 ноября 2010

Вам не нужен дополнительный выбор из двойного.Просто поместив переменную в круглые скобки, нужно добиться цели (не спрашивайте меня, почему):

open o_cur for  
select gmt_col, 
    cast( from_tz( cast( gmt_col as timestamp ), c_gmt ) at time zone (v_tz) as date ) as local_time, some_value 
from my_table 
where account_id = i_account_id 
    and gmt_col between v_start_time and v_end_time; 
...