JDBC ResultSet使用表别名获取列

55

假设我有一个像这样的查询:

SELECT * from table1 a, table2 b where (WHATEVER)

可能两个表有相同的列名。因此我认为,最好通过以下方式访问数据:

resultSet.getString("a.columnName");
resultSet.getString("b.columnName");

但这样会适得其反,我什么也得不到。我已经阅读了API,但它们并没有真正讨论这种情况。这样的功能是否取决于供应商?

8个回答

55

JDBC会根据查询中指定的名称来简单命名列 - 它不知道表名等信息。

您有两个选项:

选项1:在查询中以不同的方式命名列,例如

SELECT
    a.columnName as columnNameA,
    b.columnName as columnNameB,
    ...
from table1 a, table2 b where (WHATEVER)

然后在您的Java代码中引用列别名:

resultSet.getString("columnNameA");
resultSet.getString("columnNameB");


选项2: 在调用JDBC API时请参考position列:

resultSet.getString(1);
resultSet.getString(2);

请注意,JDBC API使用基于1的索引——即它们从1开始计数(而不是像Java索引一样从0开始),因此在第一列使用1,在第二列使用2,以此类推。


我建议使用选项1,因为引用命名列更安全:有人可能会更改查询中列的顺序,并且它会悄无声息地破坏您的代码(您将访问错误的列但不知道),但是如果他们更改列名称,则您至少会在运行时获得“没有这样的列”异常。


1
好的,看起来我得忘掉那个漂亮的*,给所有东西命名并使用额外的映射。 - Franz Kafka

15

ResultSetMetadata.getColumnLabel() 是你所需要的。

(编辑) 示例代码,正如评论中bharal所述。

SELECT * from table1 a, table2 b where (WHATEVER)

ResultSetMetaData rsmd = rset.getMetaData();
rsmd.getColumnLabel(1);

这是编辑后的答案,附带了一个代码片段。 - Mateen
使用SQLite JDBC驱动程序,这只会给我列名,例如username,而不是完整的a.username。有没有办法获取表别名a - Miha_x64

8

使用列别名的方法如下:

SELECT A.ID 'A_ID', B.ID 'B_ID' FROM TABLE1 AS A, TABLE2 AS B...

并指定您要检索的所有列(这是一个好习惯)。


5
如果你正在使用MySQL,只需添加


&useOldAliasMetadataBehavior=true

添加到您的连接字符串中。

之后,您可以使用这个小助手:

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

public class ResultSetHelper {

    private final Map<String, Integer> columnMap;

    public ResultSetHelper(ResultSet rs) throws SQLException {
        this.columnMap = new HashMap<>();
        ResultSetMetaData md = rs.getMetaData();
        int columnCount = md.getColumnCount();
        for (int index = 1; index <= columnCount; index++) {
            String columnName = md.getColumnLabel(index);
            if (!columnMap.containsKey(columnName)) {
                columnMap.put(columnName, index);
            }

            String tableAlias = md.getTableName(index);
            if (tableAlias != null && !tableAlias.trim().isEmpty()) {
                columnMap.put(tableAlias + "." + columnName, index);
            }
        }
    }

    public Integer getColumnIndex(String columnName) {
        return columnMap.get(columnName);
    }

    public Integer getColumnIndex(String tableAlias, String columnName) {
        return columnMap.get(tableAlias + "." + columnName);
    }

}

1

好的,看起来没有像 resultSet.getString("a.columnName"); 这样的方法, 你必须在 SQL 级别上为你的列设置别名, 但是既然有一个 getTableName(iCol) 方法,我希望 java.sql.ResultSet 的开发人员能够添加这样的功能。


0

你可以在SQL层面上使用别名。 然后通过索引检索数据。(但这种方法会使维护变成一个真正的噩梦)

SELECT a.column, b.column FROM table1 a, table2 b

String value = rs.getString(1);

0

我有一个想法,就是使用getTableName(iCol)方法获取具有重复名称的列的表名,然后创建自己的哈希键(附带表名前缀),这些键将指向正确的列索引,并通过此方式引用您的列值。这需要在开始时通过元数据进行初始循环以设置。我唯一看到的问题是您还在为表名起别名。我还没有找到一种无需在构建SQL语句时自己处理就可以从JDBC获取这些表名别名的方法。此解决方案将取决于您所获得的句法回报。


@Bohemian - 你可以使用ResultSetMetaData :: getTableName(int)函数来获取表名。虽然我不确定结果是否取决于jdbc实现。 https://docs.oracle.com/javase/7/docs/api/java/sql/ResultSetMetaData.html#getTableName(int) - inyourcorner

0

将你的SQL语句改为

SELECT a.*, b.* from table1 a, table2 b where (WHATEVER)

你可以通过表别名从结果集中读取

resultSet.getString("a.columnName");
resultSet.getString("b.columnName");

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