Nae*_*ghi 8 oracle ddl plsql temp-tables
在我们的项目中,我创建了一些全局临时表,如下所示:
CREATE GLOBAL TEMPORARY TABLE v2dtemp (
id NUMBER,
GOOD_TYPE_GROUP VARCHAR2(250 BYTE),
GOOD_CODE VARCHAR2(50 BYTE),
GOOD_TITLE VARCHAR2(250 BYTE)
)
ON COMMIT PRESERVE ROWS;
Run Code Online (Sandbox Code Playgroud)
但问题出现的时候我想放弃这张桌子.甲骨文不会让我放弃表,它说:
ORA-14452: attempt to create, alter or drop an index on temporary table already in use
Run Code Online (Sandbox Code Playgroud)
我必须在某些过程中使用此表,但可能会根据其他报告进行更改.所以我应该总是丢弃表,然后我应该用我需要的字段重新创建它.
出于某些商业原因,我必须使用它,所以我不可能使用表格或其他东西.我只能使用临时表.我尝试了提交删除行,但是当我调用我的过程来使用此表中的数据时,表中没有更多行,并且它们已被删除.
任何帮助将非常感谢,提前感谢
///编辑
public void saveJSONBatchOpenJobs(final JSONArray array, MtdReport report) {
dropAndCreateTable();
String sql = "INSERT INTO v2d_temp " +
"(ID, KARPARDAZ, GOOD_TYPE_GROUP, GOOD_CODE, GOOD_TITLE, COUNT, "
+ "FACTOR_COUNT, GHABZ_COUNT, DEAL_NO, DEAL_DATE, REQUEST_NO, REQUEST_DATE, "
+ "REQUEST_CLIENT, STATUS, TYPE, MTDREPORT_ID, GEN_SECURITY_DATA_ID) " +
"VALUES (MTD_KARPARDAZ_OPEN_JOBS_SEQ.nextval,?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
JSONArray values = array.getJSONArray(i);
if(!values.get(0).equals("null"))
ps.setString(1, values.get(0).toString());
else
ps.setNull(1, Types.VARCHAR);
if(!values.get(1).equals("null"))
ps.setString(2, values.get(1).toString());
else
ps.setNull(2, Types.VARCHAR);
if(!values.get(2).equals("null"))
ps.setString(3, values.get(2).toString());
else
ps.setNull(3, Types.VARCHAR);
if(!values.get(3).equals("null"))
ps.setString(4, values.get(3).toString());
else
ps.setNull(4, Types.VARCHAR);
if(!values.get(4).equals("null"))
ps.setBigDecimal(5, new BigDecimal(values.get(4).toString()));
else
ps.setNull(5, Types.NUMERIC);
if(!values.get(5).equals("null"))
ps.setBigDecimal(6, new BigDecimal(values.get(5).toString()));
else
ps.setNull(6, Types.NUMERIC);
if(!values.get(6).equals("null"))
ps.setBigDecimal(7, new BigDecimal(values.get(6).toString()));
else
ps.setNull(7, Types.NUMERIC);
if(!values.get(7).equals("null"))
ps.setString(8, values.get(7).toString());
else
ps.setNull(8, Types.VARCHAR);
if(!values.get(8).equals("null"))
ps.setDate(9, new Date(new Timestamp(values.getLong(8)).getDateTime()));
else
ps.setNull(9, Types.DATE);
if(!values.get(9).equals("null"))
ps.setString(10, values.get(9).toString());
else
ps.setNull(10, Types.VARCHAR);
if(!values.get(10).equals("null"))
ps.setDate(11, new Date(new Timestamp(values.getLong(8)).getDateTime()));
else
ps.setNull(11, Types.DATE);
if(!values.get(11).equals("null"))
ps.setString(12, values.get(11).toString());
else
ps.setNull(12, Types.VARCHAR);
if(!values.get(12).equals("null"))
ps.setString(13, values.get(12).toString());
else
ps.setNull(13, Types.VARCHAR);
if(!values.get(13).equals("null"))
ps.setString(14, values.get(13).toString());
else
ps.setNull(14, Types.VARCHAR);
if(!values.get(14).equals("null"))
ps.setLong(15, new Long(values.get(14).toString()));
else
ps.setNull(15, Types.NUMERIC);
if(!values.get(15).equals("null"))
ps.setLong(16, new Long(values.get(15).toString()));
else
ps.setNull(16, Types.NUMERIC);
}
@Override
public int getBatchSize() {
return array.size();
}
});
String bulkInsert = "declare "
+ "type array is table of d2v_temp%rowtype;"
+ "t1 array;"
+ "begin "
+ "select * bulk collect into t1 from d2v_temp;"
+ "forall i in t1.first..t1.last "
+ "insert into vertical_design values t1(i);"
+ "end;";
executeSQL(bulkInsert);
}
private void dropAndCreateTable() {
String dropSql = "declare c int;"
+ "begin "
+ "select count(*) into c from user_tables where table_name = upper('v2d_temp');"
+ "if c = 1 then "
+ "truncate table v2d_temp"
+ "drop table v2d_temp;"
+ " end if;"
+ "end;";
executeSQL(dropSql);
String createSql = "CREATE GLOBAL TEMPORARY TABLE v2d_temp (\n"
+ "DEAL_ID NUMBER,\n"
+ "id NUMBER,\n"
+ "karpardaz VARCHAR2(350),\n"
+ "GOOD_TYPE_GROUP VARCHAR2(250 BYTE),\n"
+ "GOOD_CODE VARCHAR2(50 BYTE),\n"
+ "GOOD_TITLE VARCHAR2(250 BYTE),\n"
+ "COUNT NUMBER,\n"
+ "FACTOR_COUNT NUMBER,\n"
+ "GHABZ_COUNT NUMBER,\n"
+ "DEAL_NO VARCHAR2(50 BYTE),\n"
+ "DEAL_DATE DATE,\n"
+ "REQUEST_NO VARCHAR2(50 BYTE),\n"
+ "REQUEST_DATE DATE,\n"
+ "REQUEST_CLIENT VARCHAR2(250 BYTE),\n"
+ "STATUS VARCHAR2(250 BYTE),\n"
+ "TYPE VARCHAR2(250 BYTE),\n"
+ "GEN_SECURITY_DATA_ID NUMBER(10),\n"
+ "MTDREPORT_ID NUMBER\n"
+ ")\n"
+ "ON COMMIT PRESERVE ROWS";
executeSQL(createSql);
}
private void executeSQL(String sql) {
Connection con = null;
try {
con = getConnection();
Statement st = con.createStatement();
st.execute(sql);
} catch (SQLException e) {
e.printStackTrace();
} finally {
if(con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
APC*_*APC 20
Oracle全局临时表不是临时对象.它们是正确的堆表.我们创建它们一次,任何会话都可以使用它们来存储仅对该会话可见的数据.
临时方面是数据在一个事务或一个会话之外不是持久的.关键的实现细节是将数据写入临时表空间而不是永久表空间.但是,数据仍然写入磁盘并从磁盘读取,因此使用全局临时表会产生显着的开销.
关键是我们不应该删除并重新创建临时表.如果您尝试将SQL Server样式逻辑移植到Oracle中,那么您应该考虑使用PL/SQL集合来维护内存中的临时数据. 了解更多.
具体原因ORA-14452是,如果会话期间包含数据,则不能删除具有会话范围持久性的全局临时表.即使表目前是空的......
SQL> create global temporary table gtt23 (col1 number)
2 on commit preserve rows
3 /
Table created.
SQL> insert into gtt23 values (1);
1 row created.
SQL> commit;
Commit complete.
SQL> delete from gtt23;
1 row deleted.
SQL> commit;
Commit complete.
SQL> drop table gtt23;
drop table gtt23
*
ERROR at line 1:
ORA-14452: attempt to create, alter or drop an index on temporary table already in use
SQL>
Run Code Online (Sandbox Code Playgroud)
解决方案是结束会话并重新连接,或者(有点奇怪)截断表然后删除它.
SQL> truncate table gtt23;
Table truncated.
SQL> drop table gtt23;
Table dropped.
SQL>
Run Code Online (Sandbox Code Playgroud)
如果某个其他会话正在使用全局临时表 - 这是可能的(因此全局命名法),那么在所有会话断开连接之前,您将无法删除该表.
因此,真正的解决方案是学习正确使用全局临时表:创建特定的全局临时表以匹配每个报告.或者,正如我所说,使用PL/SQL集合.或者,甚至,只要学会编写经过良好调优的SQL.我们经常使用临时表作为一个解决方案写得不好的查询,可以使用更好的访问路径保存.
看了你的完整代码后,流程看起来更奇怪了:
这里有很多开销和浪费的活动.您需要做的就是将您插入的数据v2d_temp直接填充 vertical_design,最好使用INSERT INTO ... SELECT*FROM语句.您将需要一些预处理来将JSON数组转换为查询,但这很容易在Java或PL/SQL中实现.
对我来说,似乎确定全局临时表不适合您的方案.
"我们的老板或其他人坚持通过他们的方式做某事,所以你不能改变它"
你有什么是老板问题而不是编程问题.因此,就StackOverflow而言,它是偏离主题的.但无论如何,这里有一些建议.
要记住的关键是我们不是在谈论对某些次优架构的妥协:你的老板明确提出的建议不会在多用户环境中起作用.所以,你的选择是:
ORA-14452错误,继续投入生产,然后使用"但你告诉我"防御,当这一切都发生了可怕的错误.这是最弱的一个.ORA-14452错误,说你已经做了一些调查,这似乎是以这种方式使用全局临时表的根本问题,但显然你忽略了一些东西.然后,问他们如何解决这个问题,因为他们之前已经实现了这个问题.这可以有几种方式,也许他们有一个解决方法,也许他们会意识到这是使用全局临时表的错误方式,也许他们会告诉你迷路.无论哪种方式,这都是最好的方法:你已经将关注提升到适当的水平.祝好运.
终止会话是解决 ORA-14452 错误的唯一方法。使用数据字典查找使用临时表的其他会话,并使用类似 的语句终止它们alter system kill session 'sid,seriall#,instance_id';。
这是 Oracle 支持文档 HOW TO DIAGNOSE AN ORA-14452 DURING DROP OF TEMPORARY TABLE (Doc ID 800506.1)中提到的“官方”解决方案。我过去曾成功地使用过这种方法,但原因略有不同。终止会话需要提升权限,并且可能很棘手;它可能需要多次杀戮、等待和重试。
由于多种原因,这个解决方案几乎肯定是一个坏主意。在实施此操作之前,您应该尝试利用此信息来证明这是错误的做法。例如,“Oracle 文档说此方法需要alter system特权,这很危险并会引发一些安全问题......”。
| 归档时间: |
|
| 查看次数: |
27143 次 |
| 最近记录: |