0

我需要创建一个 oracle 表,如果它在 Oracle 数据库中不存在,并且如果该表存在则不做任何事情,因此我编写了一个匿名块,如果我触发该查询两次或三次,该块在 SQL Developer 中工作我在 sql developer 中没有任何异常。这是我写的以下查询-

public static final String DATABASE_TABLE = "LnPData";

public static final String CREATE_SQL = "DECLARE " +
"t_count INTEGER; " +
"v_sql VARCHAR2(1000) := 'create table " +DATABASE_TABLE +
"(ID number(10,0), " +
"CGUID VARCHAR(255), " + 
"PGUID VARCHAR(255), " + 
"SGUID VARCHAR(255), " + 
"USERID VARCHAR(255), " +
"ULOC VARCHAR(255), " +
"SLOC VARCHAR(255), " +
"PLOC VARCHAR(255), " +
"ALOC VARCHAR(255), " +
"SITEID VARCHAR(255), " +
"PRIMARY KEY ( ID ))'; " +
"BEGIN " +
"SELECT COUNT(*) " +
"INTO t_count " +
"FROM user_tables " +
"WHERE table_name = '" +DATABASE_TABLE + "'; " +

"IF t_count = 0 THEN " +
"EXECUTE IMMEDIATE v_sql; " +
"END IF; " +
"END; ";

我在我的java代码中像这样执行上面的sql查询 - 第一次运行我的程序时,表被创建,但是当我第二次尝试运行同一个程序时,我总是得到以下异常。

// get the connection
LnPDataConstants.DB_CONNECTION = getDBConnection();
LnPDataConstants.STATEMENT = LnPDataConstants.DB_CONNECTION.createStatement();
LnPDataConstants.STATEMENT.executeUpdate(LnPDataConstants.CREATE_SQL);

而且我总是得到sql异常-

SQL Error: ORA-00955: name is already used by an existing object
00955. 00000 -  "name is already used by an existing object"

有什么建议为什么会在 Java 代码中发生?

PS我不想掉表

更新代码:-

public static final String CREATE_SQL = "CREATE TABLE IF NOT EXISTS " +DATABASE_TABLE +
    "(ID number(10,0), " +
    " CGUID VARCHAR(255), " + 
    " PGUID VARCHAR(255), " + 
    " SGUID VARCHAR(255), " + 
    " USERID VARCHAR(255), " +
    " ULOC VARCHAR(255), " +
    " SLOC VARCHAR(255), " +
    " PLOC VARCHAR(255), " +
    " ALOC VARCHAR(255), " +
    " SITEID VARCHAR(255), " +
    " PRIMARY KEY ( ID ))";
4

4 回答 4

4

在 PL/SQL 中使用此脚本:

DECLARE cnt NUMBER;
BEGIN
  SELECT count(*) INTO cnt FROM all_tables WHERE table_name = '<TABLE-NAME>';
  IF cnt = 0 THEN 
    EXECUTE IMMEDIATE 'CREATE TABLE <TABLE-NAME>(<COLUMN-DEFINITIONS>)'; 
  END IF;
END;

用适当的值替换<TABLE-NAME>和。<COLUMN-DEFINITIONS>

于 2012-05-27T03:06:55.380 回答
3

我也回答了你的另一个帖子。好像在这里你已经发现你的查询中有一个括号。

您的问题很容易解决:

如果你检查 user_tables 你会看到不是用双引号创建的表总是大写的——如果你想要一个区分大小写的表的话CREATE TABLE "tAbLeNamE"(test number)。您将表选择为“LnPData”,并且该表包含一个条目,即 LNPDATA。

解决方案是将 LnPData 更改为大写或仅更改查询的 where 子句:

"WHERE table_name = UPPER('" +DATABASE_TABLE + "'); " +

答案也属于您的其他问题java.sql.SQLException: ORA-00904

于 2012-05-27T09:37:50.287 回答
2

首先,您为什么需要这样做?您的代码意味着您正在创建多个名称不同的相同表。这听起来像是我最糟糕的噩梦。

如果我错了,而您只创建一个表,请不要在代码中执行此操作。先在数据库中做,然后你就完成了。如果我是正确的,那么规范化表格。添加一个额外的列username(你已经有userid?)或类似的东西,并将所有具有这种格式的数据插入到一个表中。同样,该表已经可以创建,无需动态创建。

如果您进行标准化,您可能需要更多索引,但看起来好像您可能会丢失一些索引,id当您从该表中选择时,您真的总是会有吗?


如果您觉得确实必须在应用程序代码中执行此操作,那么正如Matt 建议的那样,请不要在您的应用程序代码中执行此操作。您需要向您正在操作的架构授予创建表权限。

创建一个具有这些权限的用户并添加一个存储过程来为该用户执行此操作。然后授予您的应用程序架构对该架构的执行权限。

您还应该使用该dbms_assert来清理输入。

最后,Eggi 是正确的,您需要将对象名称大写,但dbms_assert默认情况下会这样做。

您还应该注意,调用user_tablesorall_tables将对性能产生影响。另一个不在应用程序中执行此操作的原因。

把这一切放在一起,你会得到一个看起来像这样的存储过程:

create or replace procedure create_the_table
           ( pTableName varchar2 ) is

declare

   -- Sanitize the input.
   l_table_name := dbms_assert.simple_sql_name(pTableName);
   l_exists number;

begin

   select count(*)
     into l_exists
     from all_tables
    where owner = 'MY_APPLICATION_SCHEMA'
      and table_name = l_table_name
          ;

   if l_exists = 0 then
       execute immediate 'create table ' || l_table_name ||
                             ' ( ID number(10,0),
                                 CGUID VARCHAR(255),
                                 PGUID VARCHAR(255), 
                                 SGUID VARCHAR(255), 
                                 USERID VARCHAR(255),
                                 ULOC VARCHAR(255),
                                 SLOC VARCHAR(255),
                                 PLOC VARCHAR(255),
                                 ALOC VARCHAR(255),
                                 SITEID VARCHAR(255),
                                 PRIMARY KEY ( ID )
                               )';
      -- need to grant permissions so that we can check if this
      -- is run again.
      execute immediate 'grant select on ' || l_table_name || 
                            ' to my_application_user';
   end if;

end;
/

然后

grant execute on create_the_table to my_application_user;

并打电话给...

begin
   my_create_table_user.create_the_table(table_name);
end;

基本上我的建议是:

  1. 完全不要这样做
  2. 如果您必须这样做,请在数据库中进行。
于 2012-05-27T10:58:11.940 回答
0

如果有人遇到类似问题,这应该会有所帮助:

甲骨文版本:

DECLARE
    NCOUNT NUMBER;
    V_SQL  LONG;
  BEGIN
    SELECT COUNT(*)
      INTO NCOUNT
      FROM USER_OBJECTS
     WHERE OBJECT_NAME = 'tableName';
    IF (NCOUNT <= 0) THEN
      V_SQL := ' CREATE TABLE tableName(      
      column1,       
      column2,       
      column3,       
      column4,       
      column5,            
      column6 VARCHAR2(2))';
      EXECUTE IMMEDIATE V_SQL;
    END IF;
  END;

爪哇版:

String sqlStanging = "DECLARE "
    +"NCOUNT NUMBER; "
    +"V_SQL LONG; "
    +"BEGIN "
    +"SELECT COUNT(*) INTO NCOUNT FROM USER_OBJECTS WHERE OBJECT_NAME = 'tableName' ;"
        +"IF(NCOUNT <= 0) "
        +"THEN "
        +"V_SQL:=' "
        +"CREATE TABLE tableName"
        +"("
        +"      column1, "
        +"      column2, "
        +"      column3, "
        +"      column4, "
        +"      column5, "
        +"      column6 VARCHAR2(2))';"       
        +"EXECUTE IMMEDIATE V_SQL ;"
        +"END IF; "
        +"END; "; 
于 2013-11-26T23:17:01.397 回答