我正在尝试使用JOOQ来查询Hive。 Hive SQL方言很适合MySQL方言。 现在我遇到了这些问题:
在JOOQ中解决此类问题的最佳做法是什么?
答案 0 :(得分:3)
不幸的是,扩展jOOQ以彻底支持新的SQL方言并不是非常简单。随着时间的推移,jOOQ的API不断发展,支持一系列标准和特定于供应商的SQL语法变体。虽然Apache Hive方言可能看起来与MySQL类似,但在jOOQ内部可能需要实现许多微妙的差异。 LIMIT .. OFFSET子句的不同实现只是一个问题。也就是说,使用带有“未知”或“不支持”方言的jOOQ通常不是一个好主意。
在短期内,您可能需要修补jOOQ的渲染SQL。最好的方法是使用ExecuteListener,如下所示:
收到“renderEnd()”事件后,您将能够访问呈现的SQL并使用正则表达式或您喜欢的任何技术对其进行修改。
从长远来看,如果/ #2337实施时可能有更好的解决方案(但我们可能不会实现)
答案 1 :(得分:1)
这是最脏的解决方案:)不幸的是,JOOQ用户组没有回答:(
public class CountRatingQueryBuilder {
private static final String SCORING_TABLE_NAME = "web_resource_rating";
private final Connection connection;
private final ScoringMetadata scoringMetadata;
private final SelectSelectStep select;
private final Factory create;
public CountRatingQueryBuilder(Connection connection, ScoringMetadata scoringMetadata){
this.connection = connection;
this.scoringMetadata = scoringMetadata;
create = new Factory(this.connection, SQLDialect.MYSQL);
select = create.select();
withSelectFieldsClause();
}
public CountRatingQueryBuilder withLimit(int limit){
select.limit(limit);
return this;
}
public CountRatingQueryBuilder withRegionId(Integer regionId){
select.where(REGION_ID.field().equal(regionId));
return this;
}
public CountRatingQueryBuilder withResourceTypeId(int resourceTypeId){
select.where(RESOURCE_TYPE_ID.field().equal(resourceTypeId));
return this;
}
public CountRatingQueryBuilder withRequestTimeBetween(long beginTimestamp, long endTimestamp){
select.where(REQUEST_TIME.field().between(beginTimestamp, endTimestamp));
return this;
}
public CountRatingQueryBuilder withResourceId(int resourceId){
select.where(RESOURCE_ID.field().equal(resourceId));
return this;
}
protected void withGroupByClause(){
select.groupBy(REGION_ID.field());
select.groupBy(RESOURCE_TYPE_ID.field());
select.groupBy(RESOURCE_ID.field());
select.groupBy(CONTENT_ID.field());
}
protected void withSelectFieldsClause(){
select.select(REGION_ID.field());
select.select(RESOURCE_TYPE_ID.field());
select.select(CONTENT_ID.field());
select.select(RESOURCE_ID.field());
select.select(Factory.count(HIT_COUNT.field()).as(SUM_HIT_COUNT.fieldName()));
}
protected void withFromClause(){
select.from(SCORING_TABLE_NAME);
}
protected void withOrderByClause(){
select.orderBy(SUM_HIT_COUNT.field().desc());
}
public String build(){
withGroupByClause();
withOrderByClause();
withFromClause();
return select.getSQL().replace("offset ?","");//dirty hack for MySQL dialect. TODO: we can try to implement our own SQL dialect for Hive :)
}
public List<ResultRow> buildAndFetch(){
String sqlWithPlaceholders = build();
List<ResultRow> scoringResults = new ArrayList<ResultRow>(100);
List<Record> recordResults = create.fetch(sqlWithPlaceholders, ArrayUtils.subarray(select.getBindValues().toArray(new Object[select.getBindValues().size()]),0, select.getBindValues().size()-1));//select.fetch();
for(Record record : recordResults){
ResultRowBuilder resultRowBuilder = ResultRowBuilder.create();
resultRowBuilder.withContentType(scoringMetadata.getResourceType(record.getValue(RESOURCE_TYPE_ID.fieldName(), Integer.class)));
resultRowBuilder.withHitCount(record.getValue(SUM_HIT_COUNT.fieldName(), Long.class));
resultRowBuilder.withUrl(record.getValue(CONTENT_ID.fieldName(), String.class));
scoringResults.add(resultRowBuilder.build());
}
return scoringResults;
}
}