如何确定ResultSet中是否存在列名?

89

ResultSet 包含从动态 SQL 返回的数据,如果有任何方法可以确定 ResultSet 是否包含特定列名?

例如,如果我运行 rs.getString("Column_ABC"),但实际上并不存在 "Column_ABC",将会抛出异常。

如何测试是否可以从名为 "Column_ABC" 的列中获取 ResultSet 数据?

6个回答

145

使用 ResultSetMetaData 类。

public static boolean hasColumn(ResultSet rs, String columnName) throws SQLException {
    ResultSetMetaData rsmd = rs.getMetaData();
    int columns = rsmd.getColumnCount();
    for (int x = 1; x <= columns; x++) {
        if (columnName.equals(rsmd.getColumnName(x))) {
            return true;
        }
    }
    return false;
}

我不理解为什么需要这个函数。执行的查询或存储过程应该已知结果,查询的列也应该已知。需要这样一个函数可能是设计上存在问题的迹象。


13
基本上是正确的,但 getColumnName 方法的参数从1开始而不是0。你需要使用 for (int x = 1; x <= columns; x++) - Adrian Smith
51
在一个高度动态、可由用户配置的系统中,搜索列名并不奇怪。根据用户的选择,列集可能会有很大的差异。是的,这个集合可以被确定下来,但假设它总是硬编码和已知的是不正确的。 - Gullbyrd
10
如果您想获取 SQL 查询中由 AS 子句定义的列名,可以使用 ResultSetMetaData.getColumnLabel。请注意不改变原意但确保内容通俗易懂。 - Santosh
4
建议使用equalsIgnoreCase方法来检查名称是否相同。在我的情况下,查询中有一个小写的列名,但是通过getColumnName()函数返回的是大写字母形式。 - Luca Regazzi
8
是的,DB模式应该是众所周知的。然而,你可能会遇到这样一种情况,即一个存储过程从一个JOIN返回一个列,而另一个存储过程不返回该列。为了提高性能,只进行需要的连接操作可能是好的,而不是选择不必要的列并使用默认值来匹配你的应用程序可能使用的理论模式。通过像rs.containsColumn(x)这样的方法,一个方法可以读取任何一个存储过程的结果,而不是第二种方法与第一种方法完全相同,但却少了一个rs.get***()方法。明白吗? - s.co.tt
显示剩余11条评论

24
private boolean isThere(ResultSet rs, String column){
    try{
        rs.findColumn(column);
        return true;
    } catch (SQLException sqlex){
        logger.debug("column doesn't exist {}", column);
    }

    return false;
}

10
@mjuarez,在这种情况下,“findColumn”命令返回的结果并不重要,可以忽略。 "isThere"方法肯定不总是返回true。如果未找到该列,“findColumn”会抛出SQLException。这个答案似乎没问题。 - Freddie
这个答案比Erick Robertson的答案更好、更高效吗?我正在为我们的团队和公司寻找最佳答案,谢谢。 - mattsmith5

8

我不确定这个方法是比埃里克的答案更高效还是更低效,但它更加简单易懂。

String str;

try {
    str = rs.getString(columnName);
} catch (java.sql.SQLException e) {
    str = null;
}

1
毫无疑问,这更容易理解。然而,即使我没有看到JDBC驱动程序返回“SQLServer”异常,ResultSet方法仍会在列名无效或发生更通用的SQL错误时返回SQLException(这使得了解发生了什么变得困难:是错误的列名还是实际错误)。+info @ ResultSet Javadoc - João Dias Amaro
44
异常应该只在特殊情况下使用,并且需要记录异常。采取简单的方法往往会导致难以理解和维护的代码。如果您正在使用服务器端结果集并且在进行此调用之前失去了与数据库的连接,则即使列存在,此方法也会引发异常。如果代码使用此检查(例如)确定整个数据库是否需要初始化,则此类情况可能会导致灾难性后果。 - Erick Robertson
谢谢João,你是对的。我是指SQLException。试图选择一个通用的。 - Zip184

-1

resultSet.getColumnMetaData().contains(columnName)


3
你能否根据变量名修改你的答案?同时,你能否提供一下它是如何工作的解释? - Saurabh Prakash
3
ResultSet 接口没有 getColumnMetaData 方法。 - IdontCareAboutReputationPoints

-4
/**
 * returns default value if column is not present in resultset
 * 
 * @param rs
 * @param columnLabel
 * @param defaultValue
 * @return
 */
@SuppressWarnings("unchecked")
private static <T> T getValueFromResultSet(final ResultSet rs,
        String columnLabel, T defaultValue) {
    try {
        return (T) rs.getObject(columnLabel);
    } catch (SQLException e) {
        return defaultValue;
    }
}

在Java版本>=7中,您可以在ResultSet#getObject方法中传递Class类型的选项。

1
这应该是正确的答案。这是一种安全的方式,提供从行获取对象类型的方法,以填充/映射一个对象,无论它是否被填充,客户端或基础业务逻辑都应该知道期望什么,并对其数据进行安全检查。 - thekevshow
1
我不同意,Erick Robertson在上面的评论中解释了原因。 - Pieter De Bie
3
虽然这样做能够起作用,但它滥用了异常处理的概念。 - Ben

-19

如果 rs.getString("Column_ABC") 不等于空,则 ' 在此编写您的代码


9
这是一个不好的想法,也是错误的。当列不存在时,它不会返回任何内容,而是会抛出一个SQLException异常,你需要捕获并处理它。在这样简单的检查中不应该使用抛出异常的方式。你应该总是寻找一个能够返回布尔值的方法——实际执行适当检查的方法。 - Erick Robertson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接