2014-12-13 2 views
1

Я хотел бы получить помощь, чтобы получить конкретный результат с Oracle 11gR2.Строки в столбцы с функцией LEAD/LAG

Прежде всего, мне нужно начать с таблицей «RAW_DATA» расположены так:

CREATE TABLE RAW_DATA 
AS 
SELECT 'MTL' AS EMH_CED,'ATW 25-55' AS EMH_ID,to_date('2014-12-03 17:17:10','yyyy-mm-dd hh24:mi:ss') AS EMH_DATE_HEURE,'AM' AS EMH_TYPE_MESURE,'A' AS EMH_PHASE,75 AS EMH_MESURE FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-03 17:17:10','yyyy-mm-dd hh24:mi:ss'),'AM','B',100 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-03 17:17:10','yyyy-mm-dd hh24:mi:ss'),'AM','C',98 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-03 17:17:29','yyyy-mm-dd hh24:mi:ss'),'AM','A',75 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-03 17:17:29','yyyy-mm-dd hh24:mi:ss'),'AM','B',100 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-03 17:17:29','yyyy-mm-dd hh24:mi:ss'),'AM','C',98 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-03 17:17:57','yyyy-mm-dd hh24:mi:ss'),'AM','A',84 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-03 17:17:57','yyyy-mm-dd hh24:mi:ss'),'AM','B',100 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-03 17:17:57','yyyy-mm-dd hh24:mi:ss'),'AM','C',98 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 00:00:00','yyyy-mm-dd hh24:mi:ss'),'AM','B',91 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 00:00:00','yyyy-mm-dd hh24:mi:ss'),'AM','C',89 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 15:06:07','yyyy-mm-dd hh24:mi:ss'),'AM','A',0 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 15:06:07','yyyy-mm-dd hh24:mi:ss'),'AM','B',0 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 15:06:07','yyyy-mm-dd hh24:mi:ss'),'AM','C',0 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:22:37','yyyy-mm-dd hh24:mi:ss'),'AM','A',23 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:22:37','yyyy-mm-dd hh24:mi:ss'),'AM','B',24 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:22:37','yyyy-mm-dd hh24:mi:ss'),'AM','C',24 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:27:36','yyyy-mm-dd hh24:mi:ss'),'AM','A',34 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:27:43','yyyy-mm-dd hh24:mi:ss'),'AM','B',40 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:27:43','yyyy-mm-dd hh24:mi:ss'),'AM','C',39 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:28:12','yyyy-mm-dd hh24:mi:ss'),'AM','A',51 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:28:12','yyyy-mm-dd hh24:mi:ss'),'AM','B',58 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:28:12','yyyy-mm-dd hh24:mi:ss'),'AM','C',57 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:40:33','yyyy-mm-dd hh24:mi:ss'),'AM','B',80 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:40:33','yyyy-mm-dd hh24:mi:ss'),'AM','C',78 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:41:02','yyyy-mm-dd hh24:mi:ss'),'AM','A',73 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:47:10','yyyy-mm-dd hh24:mi:ss'),'AM','A',83 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:55:39','yyyy-mm-dd hh24:mi:ss'),'AM','B',98 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:27:59','yyyy-mm-dd hh24:mi:ss'),'AM','A',0 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:27:59','yyyy-mm-dd hh24:mi:ss'),'AM','B',0 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:27:59','yyyy-mm-dd hh24:mi:ss'),'AM','C',0 FROM dual union ALL 
SELECT 'MTL','ATW 25-55',to_date('2014-12-04 16:56:37','yyyy-mm-dd hh24:mi:ss'),'AM','C',96 FROM dual; 

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

мне нужно иметь, на для каждого значения «EMH_PHASE» («A», «B» и «C»). Этот результат необходимо сохранить в трех новых столбцах, которые называются «MESURE_A», «MESURE_B» и «MESURE_C».

После этого мне нужен datarow непосредственно перед и после пересечения нуля (это когда MESURE_A=MESURE_B=MESURE_C=0, с «RAW_DATA», отсортированным по «EMH_DATE_HEURE»). Мне также нужен datarow, соответствующий пересечениям нуля. В моем контексте может быть несколько пересечений с нуля. Затем, на основе таблицы «RAW_DATA», результат я хочу получить следующий:

EMH_CED, EMH_ID,  EMH_DATE_HEURE,  EMH_TYPE_MESURE, MESURE_A, MESURE_B, MESURE_C 
MTL  ATW 25-55 2014-12-04 00:00:00  AM    84  91  89 
MTL  ATW 25-55 2014-12-04 15:06:07  AM    0   0   0 
MTL  ATW 25-55 2014-12-04 16:22:37  AM    23  24  24 
MTL  ATW 25-55 2014-12-04 16:27:43  AM    34  40  39 
MTL  ATW 25-55 2014-12-04 16:27:59  AM    0   0   0 
MTL  ATW 25-55 2014-12-04 16:28:12  AM    51  58  57 

Итак, я первый преобразовал столбец «EMH_PHASE» от «RAW_DATA» в 3-х distincts колонок («MESURE_A», «MESURE_B» и «MESURE_C») с кодом ниже.

WITH ROWS_TO_COLUMNS AS(
    SELECT EMH_CED 
    ,EMH_ID 
    ,EMH_DATE_HEURE 
    ,EMH_TYPE_MESURE 
    , MAX(decode(EMH_PHASE,'A', EMH_MESURE, null)) AS MESURE_A 
    , MAX(decode(EMH_PHASE,'B', EMH_MESURE, null)) AS MESURE_B 
    , MAX(decode(EMH_PHASE,'C', EMH_MESURE, null)) AS MESURE_C 
FROM RAW_DATA 
GROUP BY EMH_CED, EMH_ID, EMH_DATE_HEURE, EMH_TYPE_MESURE 
) 

До сих пор, похоже, я делаю то, что хочу, но получаю некоторые значения нулевых значений.

Затем я заполнил значения NULLS со значениями, которые были до каждого из них с этим кодом:

NULLS_FILLED AS(
    SELECT EMH_CED, EMH_ID, EMH_DATE_HEURE 
    ,FIRST_VALUE(MESURE_A) IGNORE NULLS 
     OVER (PARTITION BY EMH_CED, EMH_ID ORDER BY EMH_CED, EMH_ID, EMH_DATE_HEURE DESC 
     RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS MESURE_A 
    ,FIRST_VALUE(MESURE_B) IGNORE NULLS 
     OVER (PARTITION BY EMH_CED, EMH_ID ORDER BY EMH_CED, EMH_ID, EMH_DATE_HEURE DESC 
     RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS MESURE_B 
    ,FIRST_VALUE(MESURE_C) IGNORE NULLS 
     OVER (PARTITION BY EMH_CED, EMH_ID ORDER BY EMH_CED, EMH_ID, EMH_DATE_HEURE DESC 
     RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS MESURE_C 
FROM ROWS_TO_COLUMNS 
ORDER BY EMH_DATE_HEURE 
) 

Результат после этого операция была одна, я искал в самом начале.

Следующий шаг - это то, где мне нужна помощь. Я хочу получить только строки LEADing и LAGing, когда MESURE_A=MESURE_B=MESURE_C=0 (и мне тоже нужно показать эту строку).

Прямо сейчас, я могу получить только строки LAGing и самую последнюю строку таблицы, которую я даже не хочу. Мне все еще нужно выяснить способ получить 2 строки, которые я пропускаю, избавляясь от той, которую я не хочу.

Я пробовал разные вещи без каких-либо хороших результатов. Помогите?

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

,RN_DATA AS(
    SELECT NULLS_FILLED.*, row_number() over (order by EMH_CED, EMH_ID, EMH_DATE_HEURE) AS rn 
FROM NULLS_FILLED 
) 

,DATA_GROUPED AS (
    SELECT RN_DATA.*, rownum - rn AS grp 
FROM RN_DATA 
WHERE MESURE_A>0 AND MESURE_B>0 AND MESURE_C>0 
) 

SELECT max(EMH_CED) keep (dense_rank first ORDER BY EMH_CED, EMH_ID, EMH_DATE_HEURE DESC) AS EMH_CED 
    ,max(EMH_ID) keep (dense_rank first ORDER BY EMH_CED, EMH_ID, EMH_DATE_HEURE DESC) AS EMH_ID 
    ,max(EMH_DATE_HEURE) keep (dense_rank first ORDER BY EMH_CED, EMH_ID, EMH_DATE_HEURE DESC) AS EMH_DATE_HEURE 
    ,max(MESURE_A) keep (dense_rank first ORDER BY EMH_CED, EMH_ID, EMH_DATE_HEURE DESC) AS MESURE_A 
    ,max(MESURE_B) keep (dense_rank first ORDER BY EMH_CED, EMH_ID, EMH_DATE_HEURE DESC) AS MESURE_B 
    ,max(MESURE_C) keep (dense_rank first ORDER BY EMH_CED, EMH_ID, EMH_DATE_HEURE DESC) AS MESURE_C 
    ,max(rn) keep (dense_rank first ORDER BY EMH_CED, EMH_ID, EMH_DATE_HEURE DESC) AS rn 
FROM DATA_GROUPED 
GROUP BY grp 
ORDER BY rn 
; 

Не стесняйтесь проверить свой код с SQL Fiddle по адресу: http://sqlfiddle.com/#!4/e6b2e0/4/0

+0

Это роман, а не вопрос. –

ответ

1

Я не» Понимаете, почему вы используете функции ROW_NUMBER, FIRST, LAST. Вам просто нужно использовать функции LEAD, LAG.

WITH rows_to_columns AS 
(
     SELECT emh_ced, 
        emh_id, 
        emh_date_heure, 
        emh_type_mesure, 
        Max (
        CASE emh_phase 
          WHEN 'A' THEN emh_mesure 
        END) AS mesure_a, 
        Max (
        CASE emh_phase 
          WHEN 'B' THEN emh_mesure 
        END) AS mesure_b, 
        Max (
        CASE emh_phase 
          WHEN 'C' THEN emh_mesure 
        END) AS mesure_c 
     FROM  raw_data 
     GROUP BY emh_ced, 
        emh_id, 
        emh_date_heure, 
        emh_type_mesure), nulls_filled AS 
(
     SELECT emh_ced, 
        emh_id, 
        emh_date_heure, 
        emh_type_mesure, 
        First_value (mesure_a) ignore nulls over (PARTITION BY emh_ced, emh_id ORDER BY emh_ced, emh_id, emh_date_heure DESC RANGE BETWEEN CURRENT ROW AND  unbounded following) AS mesure_a, 
        first_value (mesure_b) ignore nulls over (PARTITION BY emh_ced, emh_id ORDER BY emh_ced, emh_id, emh_date_heure DESC RANGE BETWEEN CURRENT ROW AND  unbounded following) AS mesure_b, 
        first_value (mesure_c) ignore nulls over (PARTITION BY emh_ced, emh_id ORDER BY emh_ced, emh_id, emh_date_heure DESC RANGE BETWEEN CURRENT ROW AND  unbounded following) AS mesure_c, 
        lead (mesure_a, 1) over (PARTITION BY emh_ced, emh_id ORDER BY emh_ced, emh_id, emh_date_heure)                     lead_a, 
        lead (mesure_b, 1) over (PARTITION BY emh_ced, emh_id ORDER BY emh_ced, emh_id, emh_date_heure)                     lead_b, 
        lead (mesure_c, 1) over (PARTITION BY emh_ced, emh_id ORDER BY emh_ced, emh_id, emh_date_heure)                     lead_c, 
        lag (mesure_a, 1) over (PARTITION BY emh_ced, emh_id ORDER BY emh_ced, emh_id, emh_date_heure)                     lag_a, 
        lag (mesure_b, 1) over (PARTITION BY emh_ced, emh_id ORDER BY emh_ced, emh_id, emh_date_heure)                     lag_b, 
        lag (mesure_c, 1) over (PARTITION BY emh_ced, emh_id ORDER BY emh_ced, emh_id, emh_date_heure)                     lag_c 
     FROM  rows_to_columns) 
SELECT emh_ced, 
     emh_id, 
     emh_date_heure, 
     emh_type_mesure, 
     mesure_a, 
     mesure_b, 
     mesure_c 
FROM  nulls_filled 
WHERE (
        mesure_a = 0 
     AND  mesure_b = 0 
     AND  mesure_c = 0) 
OR  (
        lead_a = 0 
     AND  lead_b = 0 
     AND  lead_c = 0) 
OR  (
        lag_a = 0 
     AND  lag_b = 0 
     AND  lag_c = 0) 
ORDER BY 3; 

Output:

| EMH_CED | EMH_ID |     EMH_DATE_HEURE | EMH_TYPE_MESURE | MESURE_A | MESURE_B | MESURE_C | 
|---------|-----------|---------------------------------|-----------------|----------|----------|----------| 
|  MTL | ATW 25-55 | December, 04 2014 00:00:00+0000 |    AM |  84 |  91 |  89 | 
|  MTL | ATW 25-55 | December, 04 2014 15:06:07+0000 |    AM |  0 |  0 |  0 | 
|  MTL | ATW 25-55 | December, 04 2014 16:22:37+0000 |    AM |  23 |  24 |  24 | 
|  MTL | ATW 25-55 | December, 04 2014 16:27:43+0000 |    AM |  34 |  40 |  39 | 
|  MTL | ATW 25-55 | December, 04 2014 16:27:59+0000 |    AM |  0 |  0 |  0 | 
|  MTL | ATW 25-55 | December, 04 2014 16:28:12+0000 |    AM |  51 |  58 |  57 | 
+0

Спасибо за ваш быстрый ответ! Я не специалист по SQL-запросам, поэтому до сих пор я всегда использовал функции ROW_NUMBER, FIRST, LAST для такого рода лечения, поэтому я не пытался использовать другие функции ...Более того, я бы не подумал использовать новые столбцы для хранения результатов функций LEAD/LAG. Ваше решение удивительно просто и делает именно то, что я хочу, большое вам спасибо! – JGLord

Смежные вопросы