互联网,请帮忙!
我正在使用 Oracle DB v 12c,其中发票开具时间在类型为 NUMBER 的列中存储为 unix 时间戳,还有一个 VARCHAR2(128) 列,它定义发票开具的时区,例如“欧洲/伦敦'。
因此可以像这样查询在本地日期“2020-10-10”开具的发票:
SELECT inv.invoiceID
FROM invoices inv
WHERE TO_CHAR(
FROM_TZ(timestamp '1970-01-01 00:00:00'
+ NUMTODSINTERVAL(inv.INVOICETIME, 'SECOND'), 'UTC') AT TIME ZONE inv.timezoneName,
'YYYY-MM-DD') = '2020-10-10';
但不幸的是,此查询不可索引。
问题是,这不起作用:
CREATE INDEX Invoices_InvoiceDate ON Invoices (
TO_CHAR(
FROM_TZ(timestamp '1970-01-01 00:00:00'
+ NUMTODSINTERVAL(INVOICETIME, 'SECOND'), 'UTC') AT TIME ZONE timezoneName,
'YYYY-MM-DD')
);
错误: ORA-01743: 只能索引纯函数
因为使用了“AT TIME ZONE”,这个算子的“纯版本”是什么?或者换句话说 - 如何在 Oracle 中将 Unix 时间戳属性转换为本地日期?
答案 0 :(得分:0)
正如@mathguy 已经解释的那样,您不能在特定时区创建索引:
CREATE INDEX IND_INVOICETIME_LOCAL ON INVOICE (
(TIMESTAMP '1970-01-01 00:00:00 UTC' + NUMTODSINTERVAL(INVOICETIME, 'SECOND')) AT TIME ZONE timezoneName
);
ORA-01743: only pure functions can be indexed
您可以做的是在 UTC 时间创建索引:
CREATE INDEX IND_INVOICETIME_UTC ON INVOICE (
TIMESTAMP '1970-01-01 00:00:00 UTC' + NUMTODSINTERVAL(INVOICETIME, 'SECOND')
);
那么条件是这样的:
WHERE TIMESTAMP '1970-01-01 00:00:00 UTC' + NUMTODSINTERVAL(INVOICETIME, 'SECOND')
BETWEEN FROM_TZ(TIMESTAMP '2020-10-10 00:00:00', timezoneName)
AND FROM_TZ(TIMESTAMP '2020-10-10 23:59:59', timezoneName)
Oracle 总是在 UTC 时间比较 TIMESTAMP WITH TIME ZONE
值。 注意,当您有一个TIMESTAMP WITH TIME ZONE
列并在其上创建索引时,Oracle 会添加一个虚拟列SYS_EXTRACT_UTC(...)
,并在此虚拟列上创建索引。正确使用此类索引/列可能具有挑战性,请参阅 https://tonyhasler.wordpress.com/2010/09/04/tonys-tirade-against-timestamp-with-time-zone/
我认为正确的用法是这样的:
WHERE SYS_EXTRACT_UTC(TIMESTAMP '1970-01-01 00:00:00 UTC' + NUMTODSINTERVAL(INVOICETIME, 'SECOND') )
BETWEEN SYS_EXTRACT_UTC(FROM_TZ(TIMESTAMP '2020-10-10 00:00:00', inv.timezoneName))
AND SYS_EXTRACT_UTC(FROM_TZ(TIMESTAMP '2020-10-10 23:59:59', inv.timezoneName))