代码之家  ›  专栏  ›  技术社区  ›  Capacytron

jooq扩展了现有的方言。采用MySQL方言到apache Hive方言

  •  2
  • Capacytron  · 技术社区  · 12 年前

    我正试图用JOOQ来征服蜂巢。 Hive SQL方言相当于MySQL方言。 现在我遇到了以下问题:

    • Hive支持LIMIT N,不支持LIMIT N-OFFSET K.Dummy 解决方案-覆盖 select。limit(限制);

    解决JOOQ中此类问题的最佳实践是什么?

    2 回复  |  直到 12 年前
        1
  •  3
  •   Lukas Eder    10 年前

    不幸的是,扩展jOOQ以完全支持一种新的SQL方言并不是很简单。随着时间的推移,jOOQ的API已经扩展,支持一组标准和特定于供应商的SQL语法变体。虽然Apache Hive方言可能看起来与MySQL相似,但jOOQ的内部可能需要实现许多细微的差异。LIMIT的不同实施方式。。OFFSET条款只是一个问题。也就是说,将jOOQ与“未知”或“不受支持”的方言一起使用通常不是一个好主意。

    解决方案:短期内

    从短期来看,您可能需要修补jOOQ渲染的SQL。实现这一点的最佳技术是使用ExecuteListener,如本文所述:

    收到“renderEnd()”事件后,您将能够访问渲染的SQL,并使用正则表达式或您喜欢的任何技术对其进行修改。

    解决方案:从长远来看

    从长远来看,如果/当 #2337 已实现(但我们可能不会实现)

        2
  •  1
  •   Capacytron    12 年前

    这是最肮脏的解决方案:)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;
        }
    
    }