Лаг и привести к следующему месяцу - PullRequest
0 голосов
/ 12 сентября 2018
TABLE: HIST
CUSTOMER   MONTH   PLAN
1          1       A
1          2       B
1          2       C
1          3       D

Если я сделаю запрос:

select h.*, lead(plan) over (partition by customer order by month) np from HIST h

Я получаю:

CUSTOMER   MONTH   PLAN   np
1          1       A      B
1          2       B      C
1          2       C      D
1          3       D      (null)

Но я хотел

CUSTOMER   MONTH   PLAN   np
1          1       A      B
1          2       B      D
1          2       C      D
1          3       D      (null)

Причина в следующем месяце для 2 - 3, с D. Я думаю, partition by customer order by month не работает так, как я думал.

Есть ли способ добиться этого в Oracle 12c?

Ответы [ 3 ]

0 голосов
/ 12 сентября 2018

Вы можете использовать LAG / LEAD дважды. Первый раз, чтобы проверить наличие повторяющихся месяцев и установить значение NULL в эти месяцы, а второй раз использовать IGNORE NULLS, чтобы получить следующее месячное значение.

Он имеет дополнительное преимущество: если пропущены месяцы, он все равно найдет следующее значение.

SQL Fiddle

Настройка схемы Oracle 11g R2 :

CREATE TABLE HIST ( CUSTOMER, MONTH, PLAN ) AS
SELECT 1, 1, 'A' FROM DUAL UNION ALL
SELECT 1, 2, 'B' FROM DUAL UNION ALL
SELECT 1, 2, 'C' FROM DUAL UNION ALL
SELECT 1, 3, 'D' FROM DUAL UNION ALL
SELECT 2, 1, 'E' FROM DUAL UNION ALL
SELECT 2, 1, 'F' FROM DUAL UNION ALL
SELECT 2, 3, 'G' FROM DUAL UNION ALL
SELECT 2, 5, 'H' FROM DUAL;

Запрос 1 :

SELECT CUSTOMER,
       MONTH,
       PLAN,
       LEAD( np ) IGNORE NULLS OVER ( PARTITION BY CUSTOMER ORDER BY MONTH, PLAN, ROWNUM ) AS np
FROM   (
  SELECT h.*,
         CASE MONTH
         WHEN LAG( MONTH ) OVER ( PARTITION BY CUSTOMER ORDER BY MONTH, PLAN, ROWNUM )
         THEN NULL
         ELSE PLAN
         END AS np
  FROM   hist h
)

Результаты

| CUSTOMER | MONTH | PLAN |     NP |
|----------|-------|------|--------|
|        1 |     1 |    A |      B |
|        1 |     2 |    B |      D |
|        1 |     2 |    C |      D |
|        1 |     3 |    D | (null) |
|        2 |     1 |    E |      G |
|        2 |     1 |    F |      G |
|        2 |     3 |    G |      H |
|        2 |     5 |    H | (null) |
0 голосов
/ 12 сентября 2018

Для того, чтобы он был указан здесь в качестве опции для Oracle 12c (далее), вы можете использовать оператор применения для этого типа проблемы

select
     h.customer, h.month, h.plan, oa.np
from hist h
outer apply (
  select
       h2.plan as np
  from hist h2
  where h.customer = h.customer
  and h2.month > h.month
  order by month
  fetch first 1 rows only
  ) oa
order by
     h.customer, h.month, h.plan

Я не знаю ни одной публичной скрипки Oracle 12c, поэтому пример в SQL Server можно найти здесь: http://sqlfiddle.com/#!18/cd95e/1

| customer | month | plan |     np |
|----------|-------|------|--------|
|        1 |     1 |    A |      C |
|        1 |     2 |    B |      D |
|        1 |     2 |    C |      D |
|        1 |     3 |    D | (null) |
0 голосов
/ 12 сентября 2018

Один из способов сделать это - использовать RANGE разбиение с аналитической функцией MIN.Например:

select h.*, 
       min(plan) over 
           (partition by customer 
            order by month 
            range between 1 following and 1 following) np 
from HIST h;
+----------+-------+------+----+
| CUSTOMER | MONTH | PLAN | NP |
+----------+-------+------+----+
|        1 |     1 | A    | B  |
|        1 |     2 | B    | D  |
|        1 |     2 | C    | D  |
|        1 |     3 | D    |    |
+----------+-------+------+----+

Когда вы используете RANGE разбиение, вы говорите Oracle сделать окна на основе значений столбцавы упорядочиваете, а не делаете окна на основе строк.

Так, например,

ROWS BETWEEN 1 following and 1 following

... создаст окно, содержащее следующую строку.

RANGE BETWEEN 1 following and 1 following

... создаст окно, содержащее все строки, имеющие следующее значение для month.

ОБНОВЛЕНИЕ

Если возможно, что некоторые значения для MONTH могут бытьпропущенный для данного клиента, вы можете использовать этот вариант:

select h.*, 
       first_value(plan) over 
          (partition by customer 
           order by month 
           range between 1 following and unbounded following) np 
from h 
+----------+-------+------+----+
| CUSTOMER | MONTH | PLAN | NP |
+----------+-------+------+----+
|        1 |     1 | A    | B  |
|        1 |     3 | B    | D  |
|        1 |     3 | C    | D  |
|        1 |     4 | D    |    |
+----------+-------+------+----+
...