• mysql、oracle 分组查询,每组取一条数据


    1.情景展示

    有这样一种需求:

    将数据按照机构进行分组,然后取每个机构下只取一条记录,如何实现?

    2.mysql

    分组查询出来某字段,然后和原来的表进行关联查询。

    方式一:通过内连接来实现

    查看代码
    SELECT
    	t3.INVOICINGPARTYCODE,
    	t3.INVOICINGPARTYNAME,
    	t2.EINVOICECODE,
    	t2.EINVOICENUMBER,
    	t2.CARDNO,
    	t2.PAYERPARTYCODE,
    	t2.PAYERPARTYNAME 
    FROM
    	(
    	SELECT
    		ORGID,
    		max( ID ) ID 
    	FROM
    		cz_fet_main_mz 
    	WHERE
    		CARDTYPE = 01 
    		AND LENGTH( CARDNO )= 18 
    		AND KPSTATUS = 1 
    		AND DATE_FORMAT( ISSUETIME, '%Y' )= '2021' 
    	GROUP BY
    		ORGID 
    	) t,
    	cz_fet_main_mz t2,
    	cz_unitinfo t3 
    WHERE
    	t2.ORGID = t.ORGID 
    	AND t2.ID = t.ID 
    	AND t3.ORGCODE = t2.ORGID 
    ORDER BY
    	t3.CHECKCODE

    这里有两个核心点:

    第一,分组查询出来的字段,需要确保该字段在表中必须具有数据唯一性,不然的话,分组查询没有意义;

    比方说:时间,但时间也有可能重复,如果我们只精确到秒的话(毫秒也可能会重);

    如果表中没有定义唯一性字段,且确实不知道那个字段具有唯一性,最简单的方式就是表主键(表主键本身就具有唯一性)。

    第二,将查询结果当做一张表,来和之前的表建立内连接。

    上面的代码,其实还可以进行简化:

    ORGID字段可以去掉,即:

    查看代码
    SELECT
    	t3.INVOICINGPARTYCODE,
    	t3.INVOICINGPARTYNAME,
    	t2.EINVOICECODE,
    	t2.EINVOICENUMBER,
    	t2.CARDNO,
    	t2.PAYERPARTYCODE,
    	t2.PAYERPARTYNAME 
    FROM
    	(
    	SELECT
    		max( ID ) ID 
    	FROM
    		cz_fet_main_mz 
    	WHERE
    		CARDTYPE = 01 
    		AND LENGTH( CARDNO )= 18 
    		AND KPSTATUS = 1 
    		AND DATE_FORMAT( ISSUETIME, '%Y' )= '2021' 
    	GROUP BY
    		ORGID 
    	) t,
    	cz_fet_main_mz t2,
    	cz_unitinfo t3 
    WHERE
    	T2.ID = T.ID 
    	AND t3.ORGCODE = t2.ORGID 
    ORDER BY
    	t3.CHECKCODE

    执行所需时间:

    代码简化前耗费时间:

    由此可见,SQL不是越简化越快(另外,重复的where限制条件,加上也并不能提高查询速度)。

    方式二:通过exits来实现

    查看代码
    SELECT
    	t3.INVOICINGPARTYCODE,
    	t3.INVOICINGPARTYNAME,
    	t2.EINVOICECODE,
    	t2.EINVOICENUMBER,
    	t2.CARDNO,
    	t2.PAYERPARTYCODE,
    	t2.PAYERPARTYNAME 
    FROM
    	cz_fet_main_mz t2,
    	cz_unitinfo t3 
    WHERE
    	t3.ORGCODE = t2.ORGID 
    	AND EXISTS (
    	SELECT
    		1 
    	FROM
    		cz_fet_main_mz 
    	WHERE
    		CARDTYPE = 01 
    		AND LENGTH( CARDNO )= 18 
    		AND KPSTATUS = 1 
    		AND DATE_FORMAT( ISSUETIME, '%Y' )= '2021' 
    	GROUP BY
    		ORGID 
    	HAVING
    		ORGID = t2.ORGID 
    		AND INVOICENO = t2.INVOICENO 
    	) 
    ORDER BY
    	t3.CHECKCODE

    使用exists()从逻辑上应该是行得通的,但是,我并没有测试出来这种方式的真实性。

    原因在于:数量太大,查询结果太慢,用了700多秒还没执行完,所以,放弃了;

    如果你的数据量小的话,可以试试看,如果可行的话,欢迎在评论区留言,我替大家谢谢你。

    3.oracle

    内连接的语法与mysql一致,这里不再赘述。

    4.扩展

    关于计数查询count(1)

    count(1)函数,如果表中有索引的话,会自动使用索引字段进行查询;

    如果没有额外创建索引的话,会自动使用主键索引字段进行查询;(主键是唯一索引)

    如果对没有索引的字段进行计数的话,就会全表执行。

    没有使用这种方式的必要,还浪费时间。

    关于索引

    如上面所示,要进行分组查询的表,一共有1163万条数据;

    分组和查询的字段必须得走索引,如果不添加索引的话,那得查到什么时候?(数据少的话,有没有索引或者走不走索引都无所谓)

    写在最后

      哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!

     相关推荐:

  • 相关阅读:
    我很喜欢玩游戏,那么我就适合做游戏程序员吗?
    宁可多花1000元租房,也绝不要去挤半小时地铁
    996 盛行的年代,互联网人如何平衡工作和生活 ?
    互联网公司里都有哪些潜规则?
    那些拼命加班的程序员们,后来都怎么样了?
    MongoDB更需要好的模式设计 及 案例赏析
    MongoDB 提升性能的18原则(开发设计阶段)
    关于MongoDB数据库的日志解析
    实现MongoDB读写分离的“读偏好”介绍
    MongoDB分片 在部署和维护管理 中常见事项的总结
  • 原文地址:https://www.cnblogs.com/Marydon20170307/p/15702696.html
Copyright © 2020-2023  润新知