2012-05-27 34 views
0

我需要的,如果在Oracle數據庫中,如果再表中存在沒有做任何事情不存在,它創建一個Oracle表,所以對於我寫了一個匿名塊,在SQL開發人員,如果我解僱該查詢兩次或三次我沒有得到在SQL Developer中任何異常的工作。這是下面的查詢我wrote-創建一個表,如果在Oracle(使用Java)不存在

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代碼 - 當我運行我的程序第一次,表被創建,但第二次,當我嘗試運行同樣的程序,我總是得到下面的例外。

// 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代碼?

P.S.我不想刪除表

更新的代碼: -

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

回答

3

我也回答了你的其他線程。似乎在這裏你已經發現你的查詢中有一個括號。

你這裏的問題是很容易解決:

如果檢查USER_TABLES你會看到,它並沒有使用雙引號創建的表總是大寫 - 如果你想有一個表,它是區分大小寫的使用CREATE TABLE "tAbLeNamE"(test number)。您選擇該表作爲「LnPData」,並且該表包含一個LNPDATA條目。

的解決辦法是改變LnPData爲大寫字母或只是改變您的查詢的WHERE子句:

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

回答也屬於您的其他問題java.sql.SQLException: ORA-00904

+0

請勿使用對象名稱......這不值得冒險。 – Ben

+0

我只是想表現出這種可能性,但你說得對,依賴於案例的表/列是一個噩夢。他的陳述存在的問題是,他正在創建一個獨立案件對象,並且檢查不會忽略它。 – Eggi

+0

@Eggi,感謝評論,我無法理解,你能否再次解釋我,我需要做出什麼樣的改變,以及我需要做出哪些改變,你只是說我應該只對表名進行更改。只要讓它成爲UpperCase? – ferhan

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>用適當的值。

+0

此外,如果這是一個真正的企業應用程序,請記住,通常應用程序的用戶將無權修改表結構(其中包括創建和刪除表)。因此,在oracle中處理這個問題的最好方法是創建一個存儲過程來執行您想要的操作。該SP將由擁有權限的用戶擁有。然後,您將授予應用程序用戶執行SP的權限。這與unix/linux中的setuid位相似,因爲SP以擁有它的用戶身份運行。 – Matt

+0

我用最新的代碼更新了我的問題,我試着這樣做,我得到一個異常 - 「java.sql.SQLException:ORA-00922:丟失或無效的選項 ' – ferhan

+0

@Matt,任何想法爲什麼會發生? – ferhan

2

首先你爲什麼需要這樣做呢?您的代碼意味着您正在創建多個具有不同名稱的相同表格。這聽起來像是我最糟糕的噩夢。

如果我錯了,你就只有一個創建表,那麼請不要做在代碼。先在數據庫中完成,然後完成。如果我是正確的,然後正常化表。添加一個額外的列username(你已經有userid?)或類似的東西,並插入所有數據具有這種格式到一個表。這張表再次可以創建,並且不需要動態執行。

如果你規範化了,你可能需要更多的索引,但是看起來好像你可能會遺漏一些無論如何,當你從這張表中選擇時,你總是會有id


如果你覺得你真的爲此在應用程序代碼,然後,爲Matt suggests,不要在你的應用程序代碼中做到這一點。您需要爲您正在操作的架構授予創建表權限。

創建一個具有這些權限的用戶,並添加一個存儲過程以對此用戶執行此操作。然後在該模式上授予您的應用程序架構執行特權。

您還應該使用dbms_assert package來消毒輸入。

最後,Eggi is correct您需要使用大寫的對象名稱,儘管dbms_assert默認爲此。

您還應該注意,致電user_tablesall_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. 做到這一點。
+0

感謝您的評論,我認爲你很困惑,這個表中沒有用戶名和密碼的東西,名稱userid是爲了別的。根據你的描述,如果我們需要檢查表是否存在,它看起來非常複雜。 – ferhan

+0

,因爲我的要求很簡單,我需要運行我的Java應用程序,如果它不存在於數據庫中,我需要創建一個表,並且如果表存在,則不要執行任何操作。 – ferhan

+0

@Raihan,我的回答是那樣的;我也只是指出你可能不需要這樣做...... – Ben

0

的情況下,任何人都帶着類似的問題,這應該幫助:

Oracle版本:

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; "; 
相關問題