我需要生成一个ID,因为前32位是Unix时间戳值,接下来的32位是序列号。它的Java等价物是
tID = (long) timeMinutes << 32 | sequence & 0xFFFFFFFFL; // Upper 32 bits are the Unix minutes lower 32 are the sequence number
我正在尝试在SQL中创建此ID,以便我可以支持upsert。由于Oracle仅限于bitAND,我使用bitAND()来创建与上述类似的SQL。 使用bitAND的按位OR生成为
x + y - bitand(x,y)
x = timeMinutes << 32 = trunc((cast(SYS_EXTRACT_UTC(systimestamp) as date) - to_date('1-1-1970 00:00:00', 'MM-DD-YYYY HH24:Mi:SS'))*24*3600) * power(2,32)
y = sequenceNumber & 0xFFFFFFFFL = bitAND(sequenceNumber,?)
我不知道序列号的等效掩码(最后一个表达式中的问号)是什么。
答案 0 :(得分:2)
暂时忽略你为什么要这样做,0xFFFFFFFFL
是2 ^ 32 - 1,所以你可以使用:
bitand(sequence, power(2, 32) - 1)
使用固定的纪元时间:
Tue Sep 8 19:18:45 BST 2015
1441736325
...并且编写序列值2549626543,您的Java代码生成:
x: 6192210365330227200
y: 2549626543
tID: 6192210367879853743
演示Oracle代码:
set serveroutput on
declare
x number;
y number;
tID number;
begin
x := 1441736325 * power(2, 32);
y := bitand(2549626543, power(2, 32) - 1);
tID := x + y - bitand(x, y);
dbms_output.put_line('x: ' || x);
dbms_output.put_line('y: ' || y);
dbms_output.put_line('tID: ' || tID);
end;
/
PL/SQL procedure successfully completed.
x: 6192210365330227200
y: 2549626543
tID: 6192210367879853743
...得到相同的输出。
使用高于2 ^ 32的序列值,例如92549626543,也产生相同;来自Java:
x: 6192210365330227200
y: 2355313327
tID: 6192210367685540527
来自Oracle:
x: 6192210365330227200
y: 2355313327
tID: 6192210367685540527
正如@Sentinel指出的那样,bitand(x, y)
将始终为零,因为x
只有前32位,而y
只有第二位32位 - 所以没有重叠。所以你可以放弃那部分,然后做:
tID := x + y;
或者现在更长的形式没有重复:
select ((cast(sys_extract_utc(systimestamp) as date) - date '1970-01-01')
* 86400 * power(2,32)) + bitand(:sequence, power(2, 32) - 1)
from dual;
或具有相同的固定值:
select (1441736325 * power(2, 32)) + bitand(2549626543, power(2, 32) - 1)
from dual;
结果与上述相同。