2012-08-09 91 views
2

我的大文本字符串中包含10位數字的unix日期戳。我正在嘗試編寫一個查詢來搜索這些10位數字的文本字符串,並將其替換爲常規日期格式。我的轉換語句如下:在文本中查找Unix時間戳,並用sql替換

TRUNC(DATE '1970-01-01' + [timestamp]/86400),當我輸入一個值時,它完美地工作。

示例: 從雙重選擇TRUNC(DATE'1970-01-01'+ 1022089483/86400) = 22-may-02

但是我很難找到合適的方法來查找和替換。另外,我不能使用正則表達式。所以,這裏是我的理論SQL:

replace([column],'[sql to find 10-digit number]' 
      ,TRUNC(DATE '1970-01-01' + [10-digit number]/86400)) 

下面是一些示例文本:

1022089483等等等等等等等等等等1022094450等等等等等等等等 等等等等1022095218等等等等等等等等

+0

目前還不清楚你想要取代什麼。你能展示一個預期的輸入和輸出嗎? – alfasin 2012-08-09 20:12:11

+1

爲什麼你不能使用正則表達式?這正是他們所設計的。 – Ben 2012-08-09 20:50:05

+0

alfasin - 我想用相應的日期替換數字。 – user1588433 2012-08-10 03:33:10

回答

2

只是爲了好玩,以爲我會盡力去嘗試。一種功能是使用instr來查找10位數字的開頭,然後重複調用該數字並替換使用格式化日期找到的任何數字。不能肯定這是一個明智的做法,或以任何方式高效...

create or replace function epoch_offset(p_value in varchar2, p_start number) 
return number is 
    l_value varchar2(4000); 
    offset number := 0; 
    prev_offset number := 0; 
    digit_count number := 0; 
    epoch_start number := 0; 
    pos number := p_start; 
begin 
    -- replace all digits with a single one, to make searching with instr 
    -- simpler 
    l_value := translate(p_value, '1234567890', '9999999999'); 

    while true loop 
     -- find the next digit, starting as pos; first time through, pos 
     -- will be the p_start we were given, then it tracks where we have 
     -- got to 
     offset := instr(l_value, '9', pos); 

     if offset = 0 then 
      -- we didn't find a digit, check if we already had a 10-digit 
      -- number and have just reached the end 
      if digit_count = 10 then -- and pos > length(p_value) then 
       -- original value ends with a timestamp; so we have a 10-digit 
       -- number 
       exit; 
      else 
       -- no more digits, and last set we saw was short than 10; so 
       -- l_value does not contain any 10-digit numbers (at least, 
       -- after p_start) 
       epoch_start := 0; 
       exit; 
      end if; 
     end if; 

     if prev_offset > 0 and offset != prev_offset + 1 then 
      -- we've found a digit, but there's a gap since the last one 
      if digit_count = 10 then 
       -- the gap denotes the end of a 10-digit number, which is 
       -- what we're looking for 
       exit; 
      end if; 

      -- we've potentially started a new 10-digit number, so reset 
      epoch_start := offset; 
      digit_count := 0; 
      prev_offset := 0; 
     else 
      -- we've found a sequential digit 
      prev_offset := offset; 
     end if; 

     -- mark where we are 
     if digit_count = 0 then 
      -- start of a potential digit-sequence, make a note 
      epoch_start := offset; 
     end if; 
     digit_count := digit_count + 1; 
     pos := offset + 1; 
    end loop; 

    return epoch_start; 
end epoch_offset; 
/

create or replace function epoch_replace(p_value in varchar2, 
    p_start in number default 1) 
return varchar2 as 
    l_pos number; 
    l_time number; 
    l_value varchar2(4000); 
begin 
    -- for this iteration, find the start of a 10-digit number, starting 
    -- from p_start (1 on first iteration, by default) 
    l_pos := epoch_offset(p_value, p_start); 
    if l_pos > 0 then 
     -- found a 10-digit number; call this recursively before modifying - 
     -- this means we'll replace numbers with dates working from the end, 
     -- so the positions don't need to be adjusted for the difference 
     -- between the number and date lengths 
     l_value := epoch_replace(p_value, l_pos + 10); 
     -- get the 10-digit number... 
     l_time := to_number(substr(l_value, l_pos, 10)); 
     -- ... and convert it to a date, with the rest of the original value 
     -- around it 
     return substr(l_value, 1, l_pos - 1) 
      || to_char(trunc(DATE '1970-01-01' + l_time/86400), 'DD-mon-RR') 
      || substr(l_value, l_pos + 10); 
    else 
     -- didn't find a 10-digit number, so return what we started with 
     return p_value; 
    end if; 
end epoch_replace; 
/

可能還有其他的優勢情況下,它絆倒,但有一些明顯的人attmped它:

with tmp_tab as (
    select '1022089483 blah blah blah blah blah 1022094450 blah blah blah blah blah blah 1022095218 blah blah blah blah' as value from dual 
    union all 
    select 'blah 1022089483 blah 1022094450' from dual 
    union all 
    select 'blah 1022089483 98765 1022094450 1234' from dual 
    union all 
    select 'blah 1022089483 98765 1022094450 1022095218 1234 123456789 12345678901 123' from dual 
) 
select epoch_replace(value) from tmp_tab; 

EPOCH_REPLACE(VALUE) 
------------------------------------------------------------------------------------------------------------------------ 
22-may-02 blah blah blah blah blah 22-may-02 blah blah blah blah blah blah 22-may-02 blah blah blah blah 
blah 22-may-02 blah 22-may-02 
blah 22-may-02 98765 22-may-02 1234 
blah 22-may-02 98765 22-may-02 22-may-02 1234 123456789 12345678901 123 
+0

我昨天會試試這個,但耗盡時間:-)。 – Ben 2012-08-11 10:00:45

+0

感謝大家的建議。 – user1588433 2012-08-14 18:15:28