【问题标题】:Create a table if doesn't exists in the Oracle (using Java)如果 Oracle 中不存在表,则创建一个表(使用 Java)
【发布时间】:2023-03-22 08:20:01
【问题描述】:

我需要创建一个 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 代码中发生?

附注我不想放下桌子

更新代码:-

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

【问题讨论】:

    标签: java sql oracle if-statement


    【解决方案1】:

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

    &lt;TABLE-NAME&gt;&lt;COLUMN-DEFINITIONS&gt; 替换为适当的值。

    【讨论】:

    • 另外,如果这是针对真正的企业应用程序,请记住,应用程序的用户通常无权修改表结构(包括创建和删除表)。因此,在 oracle 中处理此问题的最佳方法是创建一个存储过程来执行您想要的操作。该 SP 将由具有权限的用户拥有。然后,您将授予应用程序用户执行 SP 的权限。这类似于 unix/linux 中的 setuid 位,因为 SP 以拥有它的用户身份运行。
    • 我用最新的代码更新了我的问题,我尝试这样做我得到了一个异常-java.sql.SQLException: ORA-00922: missing or invalid option
    • @Matt,知道为什么会这样吗?
    • @Oscar,我认为这种语法只适用于 mysql 我猜?有什么建议吗?
    • 如果存在则创建表 .. 就 create 语句而言,这不是 Oracle 数据库语法 .. 这就是您收到此错误的原因 ..
    【解决方案2】:

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

    你的问题很容易解决:

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

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

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

    答案也属于你的另一个问题java.sql.SQLException: ORA-00904

    【讨论】:

    • 不要使用大小写对象名称......这不值得麻烦。
    • 我只是想展示这种可能性,但你说得对,依赖于大小写的表/列.. 是使用的噩梦。他的陈述的问题是他正在创建一个独立于大小写的对象,而检查并没有忽略它。
    • @Eggi,感谢您的评论,我无法理解,您能再解释一下,我需要进行哪些更改以及需要在哪里进行更改,您是说我应该进行更改仅在表名中。就让它大写?
    • 是的,谢谢它已修复。我无法理解您给我的解决方案,为什么它不能与小写一起使用,因为它会自动转换为大写,对吗?
    • 但我的问题是,如果我只使用小写,那么默认情况下,oracle 会将其转换为大写,对吗?为什么它不适用于小写?
    【解决方案3】:

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

    如果我错了,而您只创建一个表,请不要在代码中执行此操作。先在数据库中做,然后你就完成了。如果我是正确的,那么规范化表格。添加一个额外的列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. 如果您必须这样做,请在数据库中进行。

    【讨论】:

    • 感谢您的评论,我认为您很困惑,此表中没有用户名和密码,名称 userid 用于其他内容。根据您的描述,如果我们需要检查表是否存在,看起来很复杂。
    • ,由于我的要求很简单,我需要运行我的java应用程序,如果它在数据库中不存在我需要创建一个表,如果表存在则不要做任何事。
    • @Raihan,我的回答是这样的;我只是还指出你可能不需要这样做......
    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-04
      • 2010-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多