mysql group by 查詢非聚集列


本文為博主原創,轉載請注明出處:

  mysql使用group by可以使用一些聚合函數,可以計算最大值(max(column)),最小值(min(column)),總和(sum(column)),平均數(avg(column()))等等,

在使用聚合函數的函數的時候,我們只可以查詢聚合函數相關的列,其余的列則不能進行查詢。示例如下:

  表結構如下:

CREATE TABLE `fucdn_hot_rank_domain` (
  `id` int(12) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `domain` int(11) NOT NULL COMMENT '域名id',
  `band` double NOT NULL COMMENT '帶寬,單位為B',
  `total` int(16) NOT NULL COMMENT '請求數',
  `clock` varchar(255) NOT NULL COMMENT '時間',
  PRIMARY KEY (`id`),
  UNIQUE KEY `domain` (`domain`,`clock`),
  KEY `domain_id` (`domain`)
) ENGINE=InnoDB AUTO_INCREMENT=21961394 DEFAULT CHARSET=utf8 COMMENT='域名用量熱門排行表';

  使用聚合函數查詢非聚合列:

 

查詢非聚合列的時候異常提示:

which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by,不在聚合函數之內,查詢異常。

如果要查詢非聚合函數的列,可以再嵌套一遍進行關聯查詢,

使用如下:

 

 

這種查詢的方便之處在於它可以避免寫多個sql進行多次查詢,但如果需要查詢的時候有多條,則需要手動過濾一下。項目中用到的sql如下:

select clock, band, total,domain from (
select MAX(band)as band1,domain from fucdn_hot_rank_domain
where domain 
in(11612,11613,11614,11615,11616,11617,11618,11619,11620)
and clock BETWEEN '2019-10-20 00:00:00.0' and '2019-10-20 23:59:59.0' GROUP BY domain ORDER BY band1 desc limit 20
)t join fucdn_hot_rank_domain fhrd on t.band1=fhrd.band and t.domain= fhrd.domain ORDER BY domain

之前代碼中要查詢這些數據的時候是分批次查詢的,先查詢所有數據,再根據過濾出的所有域名,計算出對應的峰值以及峰值時間。

代碼都是用的流式計算,由於數據量大,計算相對還是比較慢的,后來優化為上面的sql后,性能比之前快了兩倍多。

原來實現的代碼如下,以供警醒,哈哈

@Override
    public List<HotRankDomainResult> getHotRankDomainList(DomainCodeHelper helper) throws FucdnException {
        List<HotRankDomainResult> resultList = new ArrayList<>();
        System.out.println("<<<<<<<<<<<<<<selectTime::"+new Date());
        List<HotRankHelper> helperList = hotRankDao.getHotRankDomainList(helper);
        System.out.println(">>>>>>>>>>>>>>selectEndTime::"+new Date());

        // 計算出域名帶寬峰值,峰值時間,總流量,總請求數等
        // 1.獲取域名列表
        List<String> domainList = helperList.stream().map(HotRankHelper::getDomain).collect(Collectors.toList());

        // 2.對域名列表去重
        domainList = domainList.stream().distinct().collect(Collectors.toList());
        for (String domain : domainList) {
            HotRankDomainResult resultDetail = new HotRankDomainResult();
            // 獲取域名對應的列表數據
            List<HotRankHelper> domainResultList = helperList.stream()
                    .filter((HotRankHelper flow) -> domain.equals(flow.getDomain())).collect(Collectors.toList());
            // 計算峰值
            domainResultList = domainResultList.stream().sorted(Comparator.comparing(HotRankHelper::getBand).reversed())
                    .collect(Collectors.toList());

            // 計算總流量和請求數
            double totalFlow = domainResultList.stream().collect(Collectors.summingDouble(HotRankHelper::getBand));
            int totalRequest = domainResultList.stream().collect(Collectors.summingInt(HotRankHelper::getTotal));
            // 獲取峰值數據
            HotRankHelper topHelper = domainResultList.get(0);
            resultDetail.setMaxBand(topHelper.getBand());
            resultDetail.setMaxBandTime(topHelper.getClock());
            resultDetail.setDomain(topHelper.getDomain());
            resultDetail.setTotalFlow(totalFlow);
            resultDetail.setTotalRequest(Integer.toString(totalRequest));
            resultList.add(resultDetail);
        }
        // 對集合進行排序:降序
        resultList = resultList.stream().sorted(Comparator.comparing(HotRankDomainResult::getMaxBand).reversed())
                .collect(Collectors.toList());
        if (resultList.size() > 20) {
            // 獲取前20
            resultList = resultList.subList(0, 20);
        }
        
        System.out.println(">>>>>>>>>>>>>>sortEndTime::"+new Date());
        return resultList;
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM