【发布时间】:2017-01-20 11:38:16
【问题描述】:
我有一张超级简单的桌子test 例如
create table test (
id serial primary key,
status varchar (10)
);
insert into test (status)
values ('ready'), ('ready'),
('steady'),
('go'), ('go'), ('go'),
('new');
要获得我可以运行的汇总计数:-
1) 使用group by 的简单多行结果
select status,
count(id) as count
from test
group by status
...返回...
-------+-------
status | counts
-------+-------
go | 3
ready | 2
new | 1
steady | 1
-------+-------
2) 使用jsonb_object_agg 的单行结果
with stats as (
select status,
count(id) as count
from test
group by status
)
select jsonb_object_agg (status, count) as status_counts from stats
...返回...
--------------------------------------------------
status_counts
--------------------------------------------------
{ "go" : 3, "new" : 1, "ready" : 2, "steady" : 1 }
--------------------------------------------------
Mybatis 接口方法。
在我的 Java 代码中(通过 MyBatis)我有一个方法:-
public Map<String, Integer> selectStatusCounts();
我很想知道如何通过 MyBatis 将任一查询映射到 Map<String, Integer> Java 对象?
更新 (1)
在a_horse_with_no_name 建议和this stackover article 上,我想出了这个:-
3) 使用hstore 的单行结果
select hstore(array_agg(hs_key), array_agg(hs_value::text))
from (
select
status,
count(id) as count
from test
group by status
) x(hs_key,hs_value)
...返回...
--------------------------------------------------
status_counts
--------------------------------------------------
"go"=>"3", "new"=>"1", "ready"=>"2", "steady"=>"1"
--------------------------------------------------
使用这样的东西可能会起作用:-
现在将进行测试! :-)
更新(2)
再次感谢 a_horse_with_no_name 的贡献 - 我现在非常接近,但对 MyBatis 仍然很奇怪。这是我创建的类型处理程序(因此我可以在其他地方重用聚合):-
@MappedTypes(LinkedHashMap.class)
@MappedJdbcTypes(JdbcType.OTHER)
public class MyBatisMapHstoreToStringIntegerMap implements TypeHandler<Map<String, Integer>> {
public MyBatisMapHstoreToStringIntegerMap() {}
public void setParameter(PreparedStatement ps, int i, Map<String, Integer> map, JdbcType jdbcType) throws SQLException {
ps.setString(i, HStoreConverter.toString(map));
}
public Map<String, Integer> getResult(ResultSet rs, String columnName) throws SQLException {
return readMap(rs.getString(columnName));
}
public Map<String, Integer> getResult(ResultSet rs, int columnIndex) throws SQLException {
return readMap(rs.getString(columnIndex));
}
public Map<String, Integer> getResult(CallableStatement cs, int columnIndex) throws SQLException {
return readMap(cs.getString(columnIndex));
}
private Map<String, Integer> readMap(String hstring) throws SQLException {
if (hstring != null) {
Map<String, Integer> map = new LinkedHashMap<String, Integer>();
Map<String, String> rawMap = HStoreConverter.fromString(hstring);
for (Map.Entry<String, String> entry : rawMap.entrySet()) {
map.put(entry.getKey(), Integer.parseInt(entry.getValue())); // convert from <String, String> to <String,Integer>
}
return map;
}
return null;
}
}
...这是映射器界面...
public interface TestMapper {
public Map<String, Integer> selectStatusCounts();
}
...这里是 XML 映射器文件中的 <select>...
<select id="selectStatusCounts" resultType="java.util.LinkedHashMap">
select hstore(array_agg(hs_key), array_agg(hs_value::text)) as status_counts
from (
select
status,
count(id) as count
from test
group by status
) x(hs_key,hs_value)
</select>
但是,它返回一个Map,其中有一个名为status_counts 的条目,其值是我想要的实际地图,即{status_counts={new=1, ready=2, go=3, steady=1}}
以下是我对 PostgreSQL / MyBatis 的 maven 依赖项:-
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1201-jdbc41</version>
</dependency>
【问题讨论】:
-
为什么不使用
hstore?从 JDBC 驱动程序以Map的形式返回 -
从来没有使用过
hstore——我可以跳过它直接使用 JSONB :-)。聚合查询会是什么样子? -
我采用了
hstore解决方案,它返回了{status_counts={new=1, ready=2, go=3, steady=1}},即包含1 个条目的地图,即status_counts,而该地图又包含<String,Integer>的另一张地图——我真正想要的是Map<String,Integer>与列返回的内容保持一致。
标签: postgresql mybatis