2015-06-18 1 views
1

У меня есть таблица с четырьмя столбцами, вот как она выглядит. Я бы назвал это T_BPR_KPI_MONTHLY_VALUESOracle SQL Merge не будет выполняться над Statement

KPI_NAME_SHORT_S | MONTH_N | YEAR_N | VALUE_N 
----------------------------------------------- 
MY_KPI_1   |  1 | 2015 | 99.87 
MY_KPI_2   |  1 | 2015 | 97.62 
...    |  1 | 2015 |  ... 
MY_KPI_1   |  2 | 2015 |  ... 
...    |  ... | 2015 |  ... 

Каждый КПЭ представляет собой измерение, и каждый из них имеет ежедневные значения, которые сохраняются в другой таблице под названием T_BPR_KPI_DY. Моя цель - рассчитать и сохранить ежемесячные значения каждого KPI.

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

Я старался, чтобы операция слияния оракула была хорошим выбором для этой задачи. Идея состоит в том, чтобы проверить, существует ли запись, и если да, чем обновить ее значение, а если не вставить новую.

Это, как запрос выглядит

MERGE INTO T_BPR_KPI_MONTHLY_VALUE A 
USING(SELECT 'MY_KPI_1' AS KPI_NAME_SHORT_S, 1 AS MONTH_N, 2014 AS YEAR_N FROM DUAL) B 
ON (A.KPI_NAME_SHORT_S = B.KPI_NAME_SHORT_S) 
WHEN MATCHED THEN 
UPDATE SET VALUE_N = (select AVG(MY_KPI_1) from T_BPR_KPI_DY where DAY_D between '01.01.2014' AND '31.01.2014') 
WHEN NOT MATCHED THEN 
INSERT (KPI_NAME_SHORT_S, MONTH_N, YEAR_N, VALUE_N) VALUES ('MY_KPI_1', 1, 2014, (select AVG(MY_KPI_1) from T_BPR_KPI_DY where DAY_D between '01.01.2014' AND '31.01.2014')) 

Я учил, что вычисление Avg месячных значений на лету не плохая идея, так как вы можете видеть, у меня есть еще один запрос на выборку, который только вычисляет Avg Monthy значение для конкретного kpi. Я не уверен, что это лучшее практическое решение, но оно отлично работает, когда я выполняю этот запрос в инструменте разработчика oracle sql. однако, когда я пытаюсь выполнить его из приложения, он не работает.

Это как метод выглядит

public static void storeValuesToDb(ArrayList<String> kpiNames) throws SQLException { 

    Connection conn = getOracleJDBCConnection_DASH(); 

    int currentYear = cal.get(Calendar.YEAR); 
    int startYear = cal.get(Calendar.YEAR) - 1; 
    for (String kpiName : kpiNames) { 
     for (int i = startYear; i <= currentYear; i++) { 
      for (int j = 0; j < 12; j++) { 

       try { 
        String myMergeSQL = "" 
          + "MERGE INTO T_BPR_KPI_MONTHLY_VALUE A " 
          + "USING(SELECT '" + kpiName + "' AS KPI_NAME_SHORT_S, " + (j + 1) + " AS MONTH_N, " + i + " AS YEAR_N FROM DUAL) B ON (A.KPI_NAME_SHORT_S = B.KPI_NAME_SHORT_S) " 
          + "WHEN MATCHED THEN " 
          + "UPDATE SET VALUE_N = (select AVG(" + kpiName + ") from T_BPR_KPI_DY where DAY_D between '" + getFirstDateOfMonth(j, i) + "' AND '" + getLastDateOfMonth(j, i) + "') " 
          + "WHEN NOT MATCHED THEN " 
          + "INSERT (KPI_NAME_SHORT_S, MONTH_N, YEAR_N, VALUE_N) VALUES ('" + kpiName + "', " + (j + 1) + ", " + i + ", (select AVG(" + kpiName + ") from T_BPR_KPI_DY where DAY_D between '" + getFirstDateOfMonth(j, i) + "' AND '" + getLastDateOfMonth(j, i) + "'))"; 

        System.out.println(myMergeSQL); 

        Statement stmt_dash = conn.createStatement(); 
        stmt_dash.executeUpdate(myMergeSQL); 
        conn.commit(); 
        stmt_dash.close(); 
       } catch (SQLException ex) { 
        conn.close(); 
       } 
      } 
     } 
    } 

    conn.close(); 
} 

В терминал печатает только первый слияния SQL. Он не завершает операцию и не генерирует исключение. Он блокирует как-то и в дБ тоже ничего не происходит. Возможно, мой запрос слияния неверен или невозможно выполнить этот вид операции с помощью объекта-оператора. Если кто-то может узнать, в каких случаях эта проблема, пожалуйста, помогите.

Thx заранее

+1

Ваш улов (SQLException ex) просто закрывает соединение. Распечатайте сообщение об исключении на консоли, оно будет содержать ошибку. – LonWolf

+0

Привет, thx для повтора. Я пробовал, как вы предложили с помощью ex.printStackTrace() ', а также с' System.err.println (ex.getMessage()), но ничего не случилось. Я также удалил 'conn.close()' из блока catch, но это не помогло. однако при выполнении простой вставки sql с этим кодом он отлично работает. Это говорит вам что-то? – amsalk

+0

Как долго выберете AVG (MY_KPI_1) из T_BPR_KPI_DY, где DAY_D между '01 .01.2014 'AND '31 .01.2014'' выполнить? –

ответ

1

Я хотел бы начать с переформулировать ваш запрос слияния и решить некоторые вопросы:

  1. части ИСПОЛЬЗОВАНИЕ части MERGE на самом деле означает, что ваш «источник исходных данных». Вы используете выбор из двойного с жестко закодированными значениями. Здесь вы должны выбрать все KPI, а также вычислить Среднее по KPI. Составьте свой запрос, который выбирает все ключевые показатели эффективности с их соответствующими VALUE_N и использует их в части USING
  2. , когда согласовано, затем UPDATE SET использует значения из «источника необработанных данных», который является псевдонимом B в вашем коде, а не вычисляется внутри UPDATE пункт.
  3. Если не согласовано, то INSERT VALUES - снова используйте значения из «источника необработанных данных», который является псевдонимом B вашего кода, не пытайтесь вычислить VALUE_N внутри вставки - ну, по крайней мере, не так. Я думаю, что это главная проблема ваших запросов.
  4. MERGE INTO xxx A Используя() B, вы указали 2 псевдонимов для своих таблиц, но по линии внутри КОГДА СООТВЕТСТВУЕТ ИЛИ НЕ ВЫПОЛНИТЬ Псевдоним. Это может вызвать проблемы, если A и B имеют похожие столбцы.

пример того, как я использую сливаться в производстве: Объединить в Destination, используя выбрать из таблицы источника (внутри выбрать из источника, который вы можете также добавить другие вычисления, очевидно, в вашем случае средний)

T_REPORT_DAILY_SNAPSHOT_2G должен быть в вашем коде выберите имя КПЭ, значение и средним или все, что нужно на INSERT и UPDATE

MERGE INTO T_CELLS_2G dest 
USING (SELECT DISTINCT * 
     FROM T_REPORT_DAILY_SNAPSHOT_2G) src 
ON (dest.lac = src.lac and dest.cell_id = src.cell_id) 
WHEN MATCHED THEN 
UPDATE SET 
     dest.cell_name = src.cell_name, 
     dest.loc_code = src.loc_code, 
     dest.site_code = src.site_code, 
     dest.rac = src.rac 
WHEN NOT MATCHED THEN 
    INSERT (dest.cell_name, 
     dest.loc_code, 
     dest.site_code, 
     dest.lac, 
     dest.cell_id, 
     dest.rac) 
    VALUES (src.cell_name, 
     src.loc_code, 
     src.site_code, 
     src.lac, 
     src.cell_id, 
     src.rac); 

Надеется, что это помогает в некотором роде.

+0

Отлично! Thx, это кажется хорошим решением, но поскольку я никогда не использовал слияние, прежде чем я все еще не получаю его на 100%. Специально на 1. этапе я просто должен использовать запрос, подобный этому, например. 'SELECT * FROM T_BPR_KPI_MONTHLY_VALUES', потому что он уже содержит VALUE_N для каждого KPI за каждый месяц в 2014 и 2015 годах или мне нужно рассчитать новое значение для него? – amsalk

+0

он может быть в уже просмотренной таблице (более быстрое время выполнения, если уже в 1 таблице), или вычислить его на ходу в подзапросе в операторе using(). Удачи!:) – LonWolf