SQL相当于Java代码

时间:2015-09-08 17:14:02

标签: sql oracle

我需要生成一个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,?)

我不知道序列号的等效掩码(最后一个表达式中的问号)是什么。

1 个答案:

答案 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;

结果与上述相同。