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

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

  •  
  •   bingfengCoder · 305 天前 · 2526 次点击
    这是一个创建于 305 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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  
       305 天前
    第二个慢?
    bingfengCoder
        2
    bingfengCoder  
    OP
       305 天前
    @hxpmc 不是快慢的问题,现在不考虑性能,它们查询结果完全不一样,就是 count 值差别很大,但是从直觉上去读这两个 sql ,总感觉又没毛病
    Xinu
        3
    Xinu  
       305 天前
    没去问问 gpt 吗 现在 sql 问题一律先问 gpt
    bingfengCoder
        4
    bingfengCoder  
    OP
       305 天前
    @Xinu 问过了,结果就是人工智障,它告诉我这是两个相似的 sql ,结果也应该相似。。。。但是实际执行结果 count 相差很大
    gerryzhu0033
        5
    gerryzhu0033  
       305 天前   ❤️ 1
    left join 和 right join 后面不要用 where ,用了 where 就变普通 join 了
    inkmulberry
        6
    inkmulberry  
       305 天前
    感觉上应该是第一个 count 更大
    houfeibin
        7
    houfeibin  
       305 天前   ❤️ 1
    第二种结果是对的
    ZZ74
        8
    ZZ74  
       305 天前   ❤️ 1
    注意 left join
    第一句 p 中 project id 就算 e ,d 中没有对应的 也会被 count
    第二句 就不会有问题

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

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

    这样通过方法 1 关连后 最终表里有 6 条记录 ,count 表二和表三的 proj id 都等于 6 方法二最终结果只有一条,凑 count 表二 表三的结果分边为 2 和 3
    cccmm
        23
    cccmm  
       305 天前
    architecture 表或 project_device 表的 project_id 有重复?
    kkwa56188
        24
    kkwa56188  
       304 天前
    第一个: 你 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  
       304 天前
    @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
       304 天前
    @xuanbg 试了下,结果一致了,感谢大佬
    bingfengCoder
        27
    bingfengCoder  
    OP
       304 天前
    @kkwa56188 25 楼 大佬给出了 详细的写法,group by 可以跑起来的,结果一致了
    M48A1
        28
    M48A1  
       304 天前 via iPhone
    @ZZ74 相同想法,第一个 group by 为什么不报错…
    bingfengCoder
        29
    bingfengCoder  
    OP
       304 天前
    @M48A1 现在第一个 group by 不仅不会报错,还能得到正确的结果了 详见 25 楼 XD
    bingfengCoder
        30
    bingfengCoder  
    OP
       304 天前
    不知道为什么大家会把第一种 group by 主表字段 当成邪教用法,但是通过有效的 left join 可以很好的避免子查询产生的次数,我不太喜欢写很多个子查询然后 一个个 join ,更倾向直接 join 然后一把 group by 梭,感觉要来的更加方便
    M48A1
        31
    M48A1  
       304 天前 via iPhone
    @bingfengCoder 什么版本呀,我被淘汰了
    server sql 必须加满 group by.
    bingfengCoder
        32
    bingfengCoder  
    OP
       304 天前
    @M48A1 用的 mysql 5.7 ,mysql 8 加了 ONLY_FULL_GROUP_BY 模式 也是需要加满的
    Richared
        33
    Richared  
       304 天前
    没仔细看,但是我感觉第一个种写法 count 的值有重复的。去重下?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   980 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 19:21 · PVG 03:21 · LAX 11:21 · JFK 14:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.