2015-05-12 3 views
0

Я часто сталкивался с ситуацией, когда я хотел ограничить действие аналитической функции (или OLAP в DB2) определенным подмножеством данных. Вот пример:DB2 ограничивает аналитическую функцию для подзапроса

WITH MY_TABLE AS 
(
    SELECT 1 AS FIELD1, 'A' AS FIELD2, 1 AS FIELD3, 'X' AS FIELD4 FROM DUAL 
    UNION 
    SELECT 1 AS FIELD1, 'A' AS FIELD2, 2 AS FIELD3, 'Y' AS FIELD4 FROM DUAL 
    UNION 
    SELECT 1 AS FIELD1, 'B' AS FIELD2, 3 AS FIELD3, 'X' AS FIELD4 FROM DUAL 
    UNION 
    SELECT 1 AS FIELD1, 'A' AS FIELD2, 4 AS FIELD3, 'Z' AS FIELD4 FROM DUAL 
    UNION 
    SELECT 1 AS FIELD1, 'B' AS FIELD2, 5 AS FIELD3, 'Z' AS FIELD4 FROM DUAL 
    //... 
) 
SELECT FIRST_VALUE(FIELD4) OVER (PARTITION BY FIELD1 ORDER BY FIELD3) AS FIELD2_A 
FROM MY_TABLE 
WHERE FIELD2='A' // need that as well for 'B', 'C' etc. 

Теперь громоздкий, чтобы сделать это для всех требуемых значений FIELD2 и после этого делать JOIN или UNION, кроме того, поскольку ограничения могут быть более сложными.

Таким образом, я действительно хочу обрабатывать его в одном SELECT. Вот это испытание:

//... 
SELECT CASE WHEN FIELD2 = 'A' 
      THEN FIRST_VALUE(FIELD4) 
         OVER (PARTITION BY FIELD1 
          ORDER BY CASE WHEN FIELD2='A' THEN 0 ELSE 1 END, FIELD3) 
      ELSE NULL END AS FIELD4_A, 
     CASE WHEN FIELD2 = 'B' 
      THEN FIRST_VALUE(FIELD4) 
         OVER (PARTITION BY FIELD1 
          ORDER BY CASE WHEN FIELD2='B' THEN 0 ELSE 1 END, FIELD3) 
      ELSE NULL END AS FIELD4_B, 
     //a bit more complicated 
     CASE WHEN FIELD2 IN ('A','C') 
      THEN FIRST_VALUE(FIELD4) 
         OVER (PARTITION BY FIELD1 
          ORDER BY CASE WHEN FIELD2 IN ('A','C') THEN 0 ELSE 1 END, FIELD3) 
      ELSE NULL END AS FIELD4_AC 
FROM MY_TABLE 

Идея заключается в том, чтобы упорядочить данные, установленные WHERE-критерию, но так как там могут быть случаи, когда строки с таким ограничением не существуют в перегородке (и, таким образом, нежелательный результат будет получено), ненулевое значение возвращается только в том случае, если FIELD2 соответствует ограничению (это делается во внешнем операторе CASE).

Я предполагаю, что этот подход работает (- я еще не проверял его), но он немного сложен. Существуют ли более простые или более прямые подходы к выполнению вышеуказанной задачи?

+0

Пожалуйста, измените свой вопрос и добавить примеры данных и желаемые результаты. –

ответ

1

Почему это не делает то, что вы хотите?

SELECT FIRST_VALUE(FIELD4) OVER (PARTITION BY FIELD1, FIELD2 ORDER BY FIELD3) AS FIELD2_A 
FROM MY_TABLE 

Если вы хотите, поворачиваются в отдельные столбцы:

SELECT (CASE WHEN FIELD2 = 'A' 
      THEN FIRST_VALUE(FIELD4) OVER (PARTITION BY FIELD1, FIELD2 ORDER BY FIELD3) 
     END) as FIELD4_A, 
     (CASE WHEN FIELD2 = 'B' 
      THEN FIRST_VALUE(FIELD4) OVER (PARTITION BY FIELD1, FIELD2 ORDER BY FIELD3) 
     END) as FIELD4_B, 

EDIT:

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

SELECT FIRST_VALUE(CASE WHEN FIELD2 = 'A' THEN FIELD4 END IGNORE NULLS) OVER 
      (PARTITION BY FIELD1, FIELD2 ORDER BY FIELD3) as FIELD4_A, 
     FIRST_VALUE(CASE WHEN FIELD2 = 'B' THEN FIELD4 END IGNORE NULLS) OVER 
      (PARTITION BY FIELD1, FIELD2 ORDER BY FIELD3) as FIELD4_B, 
. . . 
+0

Разделение по связанным полям не работает напрямую, потому что ограничения могут быть более сложными, чем это (я упомянул, что в вопросе, но это явно не выяснилось). Например, в другой строке можно получить соответствующий результат, где «FIELD2 IN (« A »,« C »)». Тогда можно было бы, конечно, использовать «РАЗМЕЩЕНИЕ В СЛУЧАЕ, КОГДА FIELD2 IN (« A »,« C ») ТОГДА 1 ELSE 0 END', но это не улучшается по сравнению с данным примером в OP (который использует то же самое в' ORDER BY'). В запросе есть еще 2 очень похожих 'CASE'-оператора. – davidhigh

+0

Ваш EDIT выглядит как тот совет, который я искал. Он содержит только один оператор 'CASE'. Благодарю. – davidhigh

+0

В DB2 LUW 10.1 соответствующая команда: 'FIRST_VALUE (CASE WHEN FIELD2 = 'A' THEN FIELD4 END, 'IGNORE NULLS')'. – davidhigh

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