我有一个包含四列的表,这就是它的样子。我称它为T_BPR_KPI_MONTHLY_VALUES

 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 |     ...


每个kpi代表一个度量,并且每个kpi具有每日值,这些日值保存在另一个名为T_BPR_KPI_DY的表中。我的目标是计算并保存每个KPI的每月值。

在某一天可能仍然缺少某些kpi的每日值,并且为了精确计算月度值,我必须能够替换数据库中现有的值,并为未来的几个月和几年插入新的测试数据。

我坚信oracle sql合并操作将是此任务的不错选择。这个想法是检查一个条目是否已经存在,如果存在则更新它的值,是否不插入新条目。

这就是查询的样子

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') )


我坚信即时计算平均每月价值并不是一个坏主意,因此您可以看到我还有另一个选择查询,该查询只计算特定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

最佳答案

我将从重新编写合并查询开始并解决一些问题:


合并的使用部分实际上意味着您的“原始数据源”。您正在使用具有硬编码值的双精度选择。在这里,您应该选择所有KPI,还应按KPI计算平均值。编写查询,选择所有KPI及其核心响应VALUE_N并将其用于USING部分
当匹配时,UPDATE SET使用“原始数据源”中的值(在代码中为别名B),而不是在UPDATE子句中进行计算。
如果不匹配,则插入值-再次,使用代码中别名B的“原始数据源”中的值,不要尝试在插入内容中计算VALUE_N-至少不要以这种方式,我认为这是您的查询主要问题。
使用()B将MERGE INTO xxx A合并到表中,您为表赋予了2个别名,但是在匹配或不匹配时,您未使用别名。如果A和B具有相似的命名列,则可能会引起问题。


我如何在生产中使用合并的示例:
使用源表中的选择合并到目标中(在源中选择中,您还可以添加其他计算,显然是平均值)

T_REPORT_DAILY_SNAPSHOT_2G应该在您的代码中选择kpis名称,值和平均值,或者您需要在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);


希望这会有所帮助。

09-05 17:37