为啥对 oracle 表 ALL_TAB_COLUMNS 的本机查询由于列无效而失败?

Posted

技术标签:

【中文标题】为啥对 oracle 表 ALL_TAB_COLUMNS 的本机查询由于列无效而失败?【英文标题】:Why a native query for the oracle table ALL_TAB_COLUMNS failed due to an invalid column?为什么对 oracle 表 ALL_TAB_COLUMNS 的本机查询由于列无效而失败? 【发布时间】:2021-01-11 09:49:36 【问题描述】:

为什么我在 Spring Boot Hibernate createNativeQuery 中收到此错误 Invalid column name?我正在尝试从 oracle 数据库中获取表信息。我将我的查询放入 db eaver 它的成功,请告诉我本机查询的最佳实践如何...

Hibernate: SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE FROM ALL_TAB_COLUMNS WHERE TABLE_NAME='BPN_AKTA'
2020-09-25 10:27:53.005  WARN 60208 --- [nio-8080-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 17006, SQLState: 99999
2020-09-25 10:27:53.005 ERROR 60208 --- [nio-8080-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper   : Invalid column name
2020-09-25 10:27:53.006 ERROR 60208 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not execute query] with root cause

java.sql.SQLException: Invalid column name
Query q= em.createNativeQuery("SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE FROM ALL_TAB_COLUMNS WHERE TABLE_NAME='PC'",QueryTableAttModel.class);
List<QueryTableAttModel> tableColl =  q.getResultList();

我的模特

@Entity(name="ALL_TAB_COLUMNS")
public class QueryTableAttModel 

    public String getTABLE_NAME() 
        return TABLE_NAME;
    

    public void setTABLE_NAME(String TABLE_NAME) 
        this.TABLE_NAME = TABLE_NAME;
    


    public String getCOLUMN_NAME() 
        return COLUMN_NAME;
    

    public void setCOLUMN_NAME(String COLUMN_NAME) 
        this.COLUMN_NAME = COLUMN_NAME;
    


    public String getDATA_TYPE() 
        return DATA_TYPE;
    

    public void setDATA_TYPE(String DATA_TYPE) 
        this.DATA_TYPE = DATA_TYPE;
    

    private String TABLE_NAME;
    private String COLUMN_NAME;
    private String DATA_TYPE;
    private String id;

    @Id
    public String getId() 
        return id;
    

    public void setId(String id) 
        this.id = id;
    

【问题讨论】:

【参考方案1】:

问题是表ALL_TAB_COLUMNS没有单列主键。您应该使用基于OWNERTABLE_NAMECOLUMN_NAME 列的复合主键。

例如,您可以将@IdClass annotation 用于复合主键映射:

@Entity
@Table(name = "ALL_TAB_COLUMNS")
@IdClass(QueryTableAttModelPK.class)
public class QueryTableAttModel

   private String owner;
   private String tableName;
   private String columnName;
   private String dataType;
   
   public QueryTableAttModel()
   
   
   
   @Id
   @Column(name = "OWNER")
   public String getOwner()
   
      return owner;
   
   public void setOwner(String owner)
   
      this.owner = owner;
   

   @Id
   @Column(name = "TABLE_NAME")
   public String getTableName()
   
      return tableName;
   
   public void setTableName(String tableName)
   
      this.tableName = tableName;
   

   @Id
   @Column(name = "COLUMN_NAME")
   public String getColumnName()
   
      return columnName;
   
   public void setColumnName(String columnName)
   
      this.columnName = columnName;
   

   @Column(name = "DATA_TYPE")
   public String getDataType()
   
      return dataType;
   
   public void setDataType(String dataType)
   
      this.dataType = dataType;
   

QueryTableAttModelPK 类在哪里

import java.io.Serializable;
import java.util.Objects;

public class QueryTableAttModelPK implements Serializable

   private String owner;
   private String tableName;
   private String columnName;
   
   public QueryTableAttModelPK()
   
   
   
   public QueryTableAttModelPK(String owner, String tableName, String columnName)
   
      this.owner = owner;
      this.tableName = tableName;
      this.columnName = columnName;
   

   public String getOwner()
   
      return owner;
   
   public void setOwner(String owner)
   
      this.owner = owner;
   

   public String getTableName()
   
      return tableName;
   
   public void setTableName(String tableName)
   
      this.tableName = tableName;
   

   public String getColumnName()
   
      return columnName;
   
   public void setColumnName(String columnName)
   
      this.columnName = columnName;
   
   
   @Override
   public boolean equals(Object obj) 
      if (this == obj) return true;
      if (obj == null) return false;
      if (getClass() != obj.getClass()) return false;
      
      QueryTableAttModelPK other = (QueryTableAttModelPK) obj;
      return Objects.equals(owner, other.owner) 
          && Objects.equals(tableName, other.tableName)
          && Objects.equals(columnName, other.columnName);
   

   @Override
   public int hashCode() 
      return Objects.hash(owner, tableName, columnName);
   

然后您可以使用本机查询:

List<QueryTableAttModel> results = em.createNativeQuery(
   "select OWNER, TABLE_NAME, COLUMN_NAME, DATA_TYPE from ALL_TAB_COLUMNS where TABLE_NAME = :table",
   QueryTableAttModel.class)
.setParameter("table", "ALL_TAB_COLUMNS")
.getResultList();

jpql/hql 查询:

List<QueryTableAttModel> results = em.createQuery(
   "select q from QueryTableAttModel q where q.tableName = :table",
   QueryTableAttModel.class)
.setParameter("table", "ALL_TAB_COLUMNS")
.getResultList();

或者通过PK找实体:

QueryTableAttModel qTable = em.find(
   QueryTableAttModel.class,
   new QueryTableAttModelPK("SYS", "ALL_TAB_COLUMNS", "CHAR_LENGTH")
);

【讨论】:

以上是关于为啥对 oracle 表 ALL_TAB_COLUMNS 的本机查询由于列无效而失败?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 oracle 表索引但仍然进行全表扫描?

oracle删除分区还在编辑表中显示吗为啥

为啥 oracle 不支持在单个查询中更新多个表?

oracle表空间也就是数据文件设置为自动扩展,为啥没进行自动扩展

在Oracle中,为啥删除表分区时公共同义词会失效

为啥 Oracle 12c 查询需要在表周围加上双引号 [重复]