0

Oracleデータベースに存在しない場合はOracleテーブルを作成する必要があり、テーブルが存在する場合は何もしません。そのため、そのクエリを2回または3回実行すると、SQLDeveloperで機能する匿名ブロックを作成しました。 SQLDeveloperで例外は発生しません。これは私が書いた以下のクエリです-

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; ";

上記のSQLクエリをJavaコードでこのように実行します-最初にプログラムを実行するとテーブルが作成されますが、2回目に同じプログラムを実行しようとすると、常に以下の例外が発生します。

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

私はあなたの他のスレッドにも答えました。ここで、クエリに 1 つのブラケットから多くのブラケットがあることをすでに把握しているようです。

ここでの問題は簡単に解決できます。

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

まず、なぜこれを行う必要があるのですか?コードは、すべて異なる名前の複数の同一のテーブルを作成していることを意味します。これは私の最悪の悪夢のように聞こえます。

私が間違っていて、テーブルを 1 つしか作成していない場合は、コードで作成しないでください。最初にデータベースでそれを行い、それから完了です。私が正しければ、テーブルを正規化します。余分な列username(既にありuseridますか?) などを追加し、この形式のすべてのデータを単一のテーブルに挿入します。このテーブルも、既に作成されている可能性があり、動的に作成する必要はありません。

id正規化する場合はさらにインデックスが必要になる場合がありますが、このテーブルから選択するときに、実際には常にいくつかが欠落しているように見えますか?


本当にアプリケーション コードでこれを行う必要があると思われる場合は、Matt示唆するように、アプリケーション コードでこれを行わないでください。操作しているスキーマにテーブルの作成権限を付与する必要があります。

これらの特権を持つユーザーを作成し、ストアド プロシージャを追加して、そのユーザーにこれを実行します。次に、そのスキーマに対する実行権限をアプリケーション スキーマに付与します。

dbms_assertまた、パッケージを使用して入力をサニタイズする必要があります。

最後に、Eggi は正しく、オブジェクト名を大文字にする必要がありますが、dbms_assertこれはデフォルトで行われます。

user_tablesorの呼び出しall_tablesはパフォーマンスに影響することにも注意してください。アプリケーションでそれを行わないもう 1 つの理由。

これをすべてまとめると、次のようなストアド プロシージャが得られます。

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;

Java のバージョン:

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 に答える