我有一个超级简单的表test
,例如
create table test (
id serial primary key,
status varchar (10)
);
insert into test (status)
values ('ready'), ('ready'),
('steady'),
('go'), ('go'), ('go'),
('new');
要获得聚合计数,我可以运行: -
group by
select status,
count(id) as count
from test
group by status
...返回......
-------+-------
status | counts
-------+-------
go | 3
ready | 2
new | 1
steady | 1
-------+-------
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 }
--------------------------------------------------
在我的Java代码中(通过MyBatis)我有一个方法: -
public Map<String, Integer> selectStatusCounts();
我想知道的是如何通过MyBatis将查询映射到Map<String, Integer>
Java对象?
关于a_horse_with_no_name
建议和this stackover article我提出了这个问题: -
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"
--------------------------------------------------
使用这样的东西可能有用: -
现在测试吧! : - )
再次感谢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;
}
}
...这里是mapper界面...
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>
答案 0 :(得分:0)
最简单的方法是定义hstore_agg()
函数:
CREATE AGGREGATE hstore_agg(hstore)
(
SFUNC = hs_concat(hstore, hstore),
STYPE = hstore
);
然后你可以这样做:
select hstore_agg(hstore(status, cnt::text))
from (
select status, count(*) cnt
from test
group by status
) t;
使用当前的JDBC驱动程序Statement.getObject()
将返回Map<String, String>
。
由于hstore
仅存储字符串,因此无法返回Map<String, Integer>
答案 1 :(得分:0)
发布答案(这不完美),但又想知道是否有其他人有更好的解决方案。
我的回答是基于这个stackoverflow答案: -
Return HashMap in mybatis and use it as ModelAttribute in spring MVC
我创建了一个名为KeyValue
的POJO类: -
public class KeyValue<K, V> {
private K key;
private V value;
public KeyValue() {
}
public KeyValue(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
...并将测试映射器方法更改为...
@MapKey("key")
public Map<String, KeyValue<String, Integer>> selectStatusCounts();
请注意使用
@MapKey
参数
我正在使用“1)简单的多行结果,使用” SQL原始问题“,并将结果列更改为key
+ value
(所以它映射到新的KeyValue
对象),如下所示: -
<select id="selectStatusCounts" resultType="test.KeyValue">
select status as key,
count(id) as value
from bulk_upload
group by status
</select>
使用Java访问它实现如下: -
Map<String, KeyValue<String, Integer>> statusCounts = mapper.selectStatusCounts();
并检索例如我们所做的new
项目地图中的值: -
int numberOfstatusCounts = statusCounts.get("new").getValue();
我对这个解决方案非常满意,但我仍然更喜欢Map<String, Integer>
而不是Map<String, KeyValue<String, Integer>>
,所以不接受我的解决方案 - 这只是为了表明我是如何得到的工作的东西(现在)。