Расчет номера недели - PullRequest
       18

Расчет номера недели

0 голосов
/ 01 августа 2020

Таблица:

Column1                 
2_2020
1_2020
52_2019 

Есть ли способ вычислить предыдущую неделю из Столбца 1 (номер недели_год) как Столбец 3 (предыдущая неделя)

Вывод:

 Column1       Column3           
 2_2020        1
 1_2020        52
 52_2019       (null)

Подчеркивание в столбце 1 разделяет номер недели и год соответственно

Ответы [ 5 ]

0 голосов
/ 02 августа 2020

Вы можете использовать хитрость, воспользовавшись тем фактом, что максимальное число недель (52 или 53) меньше максимального числа минут (59). Даже если ваше первое число представляет неделю, просто ради этого запроса представьте, что оно представляет собой минуту. Затем вы можете конвертировать между строковыми типами данных и датами, используя неполную модель формата даты ('mi_yyyy'). Oracle предоставляет значения по умолчанию для других компонентов: текущий месяц для 'mm', день 01 для 'dd', час 00 для часа, секунды 00 для секунды. Затем вы можете упорядочить по «дате», построенной таким образом - порядок будет таким же, независимо от того, является ли первый компонент «номером недели» или «номером часа».

Это было бы намного проще, если бы Oracle позволял модель формата даты 'iw_yyyy', но это не так.

Также обратите внимание, что - поскольку мы хотим отображать вывод в убывающем порядке - я использую убывающий порядок в функции analyti c (и поэтому, Я должен использовать lead() вместо lag()). Это позволяет избежать необходимости дважды сортировать строки (один раз в порядке возрастания для функций analyti c, а затем снова в порядке убывания для окончательного вывода).

Как я сказал в комментарии к вашему вопросу, Я считаю, что требование проблемы неверно; вам нужно, чтобы результат был показан ниже в my_column. На всякий случай я включил в вывод и «мой», и запрошенный столбец; удалите тот, который вам не нужен, после того, как вы должным образом рассмотрите мой комментарий.

with
  sample_data(column1) as (
    select '2_2020'  from dual union all
    select '1_2020'  from dual union all
    select '52_2019' from dual
  )
select column1,
       lead(column1) 
           over (order by to_date(column1, 'mi_yyyy') desc) as my_column,
       to_char(lead(to_date(column1, 'mi_yyyy')) 
           over (order by to_date(column1, 'mi_yyyy') desc), 'fmmi') as column3
from   sample_data
;

COLUMN1   MY_COLUMN COLUMN3  
--------- --------- ---------
2_2020    1_2020    1        
1_2020    52_2019   52       
52_2019                      
0 голосов
/ 01 августа 2020

Вот SQLFIDDLE DEMO

SELECT X.WEEK_YEAR, X.NEXT_WEEK FROM (
SELECT A.WEEK_YEAR, A.WEEK, A.YEAR1, LEAD(A.WEEK) OVER(ORDER BY A.YEAR1 DESC, A.WEEK DESC) NEXT_WEEK FROM (
SELECT WEEK_YEAR, SUBSTR(WEEK_YEAR, 1, INSTR(WEEK_YEAR, '_')-1) WEEK, SUBSTR(WEEK_YEAR, INSTR(WEEK_YEAR, '_')+1) YEAR1 FROM TABLE1 ORDER BY 3 DESC, 2 DESC) A) X;
0 голосов
/ 01 августа 2020

Если вас не интересуют изменения в историческом календаре, начиная с go, тогда вы можете просто получить число с помощью регулярных выражений

SELECT
  Column1, 
  DECODE(TO_NUMBER(REGEXP_SUBSTR(Column1, '^\d+')) - 1, 
         0, 52, 
         TO_NUMBER(REGEXP_SUBSTR(Column1, '^\d+')) - 1) as Column3
FROM Table
0 голосов
/ 01 августа 2020

Это паршивый формат, потому что он не сохраняет порядок. Я бы порекомендовал изменить его на YYYY_WW - поэтому значения будут 2019_52, 2020_01, 2020_02. Тогда вы можете просто использовать:

select lag(col) over (order by col)
from t;

Если это не так, как лучше всего преобразовать это в формат, сохраняющий порядок? К сожалению, Oracle to_date() не позволяет вводить недели. Но он позволяет вводить день года, и это сохраняет порядок. Таким образом, вы можете использовать:

select col,  lag(col) over (order by to_date(col, 'DDD_YYYY'))
from mytable

Здесь - скрипт db <>.

Если у вас есть дубликаты в таблице, но данные за предыдущую неделю все еще нужны , то это сложнее. Вот одно решение:

select col,
       max(col) over (order by seqnum range between 1 preceding and 1 preceding)
from (select t.*, dense_rank() over (order by to_date(col, 'DDD_YYYY')) as seqnum
      from t
     ) t;
0 голосов
/ 01 августа 2020

Вы можете использовать lag() - но вам нужно правильно разделить строку и превратить части в числа, чтобы вы могли использовать их для упорядочивания записей:

select 
    column1,
    lag(column1) over(order by 
        to_number(substr(column1, instr(column1, '_') + 1)),
        to_number(substr(column1, 1, instr(column1, '_') - 1))
    ) column3
from mytable

Демо в DB Fiddle :

with mytable as (
    select '2_2020' column1 from dual
    union all select '1_2020' from dual
    union all select '52_2019' from dual
)
select 
    column1,
    lag(column1) over(order by 
        to_number(substr(column1, instr(column1, '_') + 1)),
        to_number(substr(column1, 1, instr(column1, '_') - 1))
    ) column3
from mytable
COLUMN1 | COLUMN3
:------ | :------
52_2019 | <em>null</em>   
1_2020  | 52_2019
2_2020  | 1_2020 
...