V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
bingfengCoder
V2EX  ›  Java

请教一个 SQL 的问题,来个大佬帮忙丁真下

  •  
  •   bingfengCoder · 2024-01-31 16:17:00 +08:00 · 2606 次点击
    这是一个创建于 368 天前的主题,其中的信息可能已经有所发展或是发生改变。
    SELECT
    	p.project_code AS 项目编码,
    	p.project_name AS 项目名称,
    	count( e.id ) AS 建筑数量,
    	count( d.id ) AS 设备数量 
    FROM
    	`emp_project` p
    	LEFT JOIN `architecture` e ON p.id = e.`project_id` 
    	AND e.`is_active` = 1 
    	AND e.`level` = 30 
    	AND e.`source_type` = 'Z'
    	LEFT JOIN `project_device` d ON p.id = d.project_id 
    	AND d.is_active = 1 
    	AND d.device_type IN ( 1, 2, 3, 4 ) 
    WHERE
    	p.`is_active` = 1 
    	AND p.`source_type` = 'Z' 
    GROUP BY
    	p.id
    
    SELECT
    	p.project_code AS 项目编码,
    	p.project_name AS 项目名称,
    	en.encount AS 建筑数量,
    	de.decount AS 设备数量 
    FROM
    	`emp_project` p
    	LEFT JOIN ( SELECT `project_id`, count(*) AS encount FROM `architecture` WHERE `level` = 30 AND `is_active` = 1 
    	AND `source_type` = 'Z' GROUP BY `project_id` ) en ON p.id = en.`project_id`
    	LEFT JOIN (
    	SELECT
    		`project_id`,
    		count(*) AS decount 
    	FROM
    		`project_device` 
    	WHERE
    		`is_active` = 1 
    		AND `device_type` IN ( 1, 2, 3, 4 ) 
    	GROUP BY
    		`project_id` 
    	) de ON p.id = de.project_id 
    WHERE
    	p.`is_active` = 1 
    	AND p.`source_type` = 'Z'
    

    这两段 sql 在同一个库里执行,结果天差地别,但是从连接和分组以及查询条件来看,感觉不出来有什么差异,大佬们能不能一眼丁真帮看下原因

    33 条回复    2024-02-01 15:36:51 +08:00
    hxpmc
        1
    hxpmc  
       2024-01-31 16:23:15 +08:00
    第二个慢?
    bingfengCoder
        2
    bingfengCoder  
    OP
       2024-01-31 16:28:15 +08:00
    @hxpmc 不是快慢的问题,现在不考虑性能,它们查询结果完全不一样,就是 count 值差别很大,但是从直觉上去读这两个 sql ,总感觉又没毛病
    Xinu
        3
    Xinu  
       2024-01-31 16:38:46 +08:00
    没去问问 gpt 吗 现在 sql 问题一律先问 gpt
    bingfengCoder
        4
    bingfengCoder  
    OP
       2024-01-31 16:40:06 +08:00
    @Xinu 问过了,结果就是人工智障,它告诉我这是两个相似的 sql ,结果也应该相似。。。。但是实际执行结果 count 相差很大
    gerryzhu0033
        5
    gerryzhu0033  
       2024-01-31 16:50:43 +08:00   ❤️ 1
    left join 和 right join 后面不要用 where ,用了 where 就变普通 join 了
    inkmulberry
        6
    inkmulberry  
       2024-01-31 16:57:15 +08:00
    感觉上应该是第一个 count 更大
    houfeibin
        7
    houfeibin  
       2024-01-31 16:59:49 +08:00   ❤️ 1
    第二种结果是对的
    ZZ74
        8
    ZZ74  
       2024-01-31 17:00:25 +08:00   ❤️ 1
    注意 left join
    第一句 p 中 project id 就算 e ,d 中没有对应的 也会被 count
    第二句 就不会有问题

    而且现在 sql 都那么宽泛了吗? 第一句 sql 你 count 的话 不应该是 group by project_code 和 name 为啥要是 id...
    怎么说呢 你这两个统计值应该做成两个 sql 用 inner join....
    jorinabill111
        9
    jorinabill111  
       2024-01-31 17:04:00 +08:00
    逆天丁真
    8355
        10
    8355  
       2024-01-31 17:08:19 +08:00
    sql1 的 join 2 次纬度差异 导致的 count 数量不对吧
    从来没有想过这种魔法的操作

    你的主 sql 本身与 e/d 表条件没有任何关联就应该单独直接 sql count
    8355
        11
    8355  
       2024-01-31 17:10:05 +08:00
    @ZZ74 确实 group by 主表 id 的操作还是第一次见。。。 十分之 6
    bingfengCoder
        12
    bingfengCoder  
    OP
       2024-01-31 17:10:05 +08:00
    @inkmulberry 是的,第一个 count 会比较大,但是这种大是不准确的,找不到原因
    5sheep
        13
    5sheep  
       2024-01-31 17:13:37 +08:00
    笛卡尔乘积造成的
    bingfengCoder
        14
    bingfengCoder  
    OP
       2024-01-31 17:17:41 +08:00
    @ZZ74 试过 group by project_code,name 和 group by id 结果是一样的,count 都不准确。。。。
    ZZ74
        15
    ZZ74  
       2024-01-31 17:18:39 +08:00
    @bingfengCoder
    注意这句 注意 left join
    第一句 p 中 project id 就算 e ,d 中没有对应的 也会被 count
    ivvei
        16
    ivvei  
       2024-01-31 17:30:41 +08:00 via Android
    语法都不对,这是 mysql 吧?
    liprais
        17
    liprais  
       2024-01-31 17:32:57 +08:00
    建议你再学学
    真是一眼就能看出区别
    mytoroto
        18
    mytoroto  
       2024-01-31 18:02:38 +08:00
    同意楼上,再学学,你这是基本功有问题啊
    mytoroto
        19
    mytoroto  
       2024-01-31 18:04:56 +08:00
    @mytoroto 回错楼了
    bingfengCoder
        20
    bingfengCoder  
    OP
       2024-01-31 18:37:49 +08:00
    @mytoroto 能细说下吗
    bingfengCoder
        21
    bingfengCoder  
    OP
       2024-01-31 18:38:24 +08:00
    @liprais 能展开说下吗,想知道问题出在哪里
    sorcerer
        22
    sorcerer  
       2024-01-31 21:13:44 +08:00 via Android
    最简单的情况
    表 1 一条记录 表二满足 join 条件的有两条记录 也就是 project id 一样的有两条 表三 project id 一样的有 3 条

    这样通过方法 1 关连后 最终表里有 6 条记录 ,count 表二和表三的 proj id 都等于 6 方法二最终结果只有一条,凑 count 表二 表三的结果分边为 2 和 3
    cccmm
        23
    cccmm  
       2024-01-31 22:52:18 +08:00
    architecture 表或 project_device 表的 project_id 有重复?
    kkwa56188
        24
    kkwa56188  
       2024-02-01 05:00:14 +08:00
    第一个: 你 group by 什么字段, 就只能 select 什么字段, 其余列需要是 agg 函数, 不知道怎么跑的起来的.

    第二个: (看了一半 算了, 你为什么要这么写, 还不如重写, 见下面三)

    三: 这本身是个简单的查询, p 主表就不动它了, 不 join 不 GroupBy, 两个子表的话 再在子查询里 join 完了再 count 就好了,
    这样: select p.id, ( 子查询 1 select count(e.id) ), ( 子查询 2 select count(d.id)) from p
    xuanbg
        25
    xuanbg  
       2024-02-01 08:04:30 +08:00
    @bingfengCoder 第一种的 count 其实是右表的行数,第二种 count 的是右表 id 的个数。
    在 count 函数里面加 distinct ,写成以下的代码,结果就一致了:
    SELECT
    p.project_code AS 项目编码,
    p.project_name AS 项目名称,
    count(distinct e.id ) AS 建筑数量,
    count(distinct d.id ) AS 设备数量
    FROM
    `emp_project` p
    LEFT JOIN `architecture` e ON p.id = e.`project_id`
    AND e.`is_active` = 1
    AND e.`level` = 30
    AND e.`source_type` = 'Z'
    LEFT JOIN `project_device` d ON p.id = d.project_id
    AND d.is_active = 1
    AND d.device_type IN ( 1, 2, 3, 4 )
    WHERE
    p.`is_active` = 1
    AND p.`source_type` = 'Z'
    GROUP BY
    p.id
    bingfengCoder
        26
    bingfengCoder  
    OP
       2024-02-01 09:55:11 +08:00
    @xuanbg 试了下,结果一致了,感谢大佬
    bingfengCoder
        27
    bingfengCoder  
    OP
       2024-02-01 10:02:22 +08:00
    @kkwa56188 25 楼 大佬给出了 详细的写法,group by 可以跑起来的,结果一致了
    M48A1
        28
    M48A1  
       2024-02-01 10:15:21 +08:00 via iPhone
    @ZZ74 相同想法,第一个 group by 为什么不报错…
    bingfengCoder
        29
    bingfengCoder  
    OP
       2024-02-01 10:20:58 +08:00
    @M48A1 现在第一个 group by 不仅不会报错,还能得到正确的结果了 详见 25 楼 XD
    bingfengCoder
        30
    bingfengCoder  
    OP
       2024-02-01 10:23:15 +08:00
    不知道为什么大家会把第一种 group by 主表字段 当成邪教用法,但是通过有效的 left join 可以很好的避免子查询产生的次数,我不太喜欢写很多个子查询然后 一个个 join ,更倾向直接 join 然后一把 group by 梭,感觉要来的更加方便
    M48A1
        31
    M48A1  
       2024-02-01 10:31:03 +08:00 via iPhone
    @bingfengCoder 什么版本呀,我被淘汰了
    server sql 必须加满 group by.
    bingfengCoder
        32
    bingfengCoder  
    OP
       2024-02-01 10:50:23 +08:00
    @M48A1 用的 mysql 5.7 ,mysql 8 加了 ONLY_FULL_GROUP_BY 模式 也是需要加满的
    Richared
        33
    Richared  
       2024-02-01 15:36:51 +08:00
    没仔细看,但是我感觉第一个种写法 count 的值有重复的。去重下?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1978 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 08:52 · PVG 16:52 · LAX 00:52 · JFK 03:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.