问一个需要递归的SQL

@Ta 2022-10-09发布,2022-10-09修改 2349点击

image.png(30.36 KB)

Mysql5.7(其实是 SqlServer)
目前我的尝试, 只能递归出 所有的符合浙江省的 ,市,区,街道,不能 把 区、街道 归入到市

;with org_union  as (
  select id,name ,parent_id from org where  parent_id=1 
  UNION ALL
  select   org.id, org.name,org.parent_id  as level from org  org  JOIN org_union on org.parent_id=org_union.id


  --统计区&市 级别,level为3&2,隶属于parent_id=1 浙江省
)


SELECT top 500  org_union.org_name ,count(org_union.org_name) as CountNum,sum(order.price) as TotalTncome

from org_union as org_union 

LEFT join order as  order on  org_union.id=order.apply_org_id  

where order.pay_state=2

GROUP BY  org_union.name
回复列表(13|隐藏机器人聊天)
  • @Ta / 2022-10-09 / /

    @胡椒舰长,可以用 (Recursive) CTE,也可以直接几层 JOIN (因为你的 area_level 层数有限)

  • @Ta / 2022-10-09 / /

    @无名啊,层数是没有上限的,这里只是测试,怎么怎么想办法递归的时候统计

  • @Ta / 2022-10-09 / /

    @胡椒舰长,不会吧,area_level 还能有十几层嘛。。这是精确到一口井的收入了嘛。。

  • @Ta / 2022-10-09 / /

    @胡椒舰长,这是 (Recursive) CTE 的一个例子

    结果

    地级市 总收入 无用列
    杭州市机构 7.13 1
    温州市机构 1.03 1
    宁波市机构 1.32 1

    SQLite 实现

    (用 SQLite 意为:连 1~2 MB 的 SQLite 都支持的功能,其他数据库肯定都支持,容易移植)

    WITH RECURSIVE
      
      query(root_name) AS (
        VALUES ('浙江省机构')
      ),
      
      org(id, parent_id, name, area_level) AS (
        VALUES
          ( 8001,  1001, '浙江省机构', 2),
          (10000,  8001, '杭州市机构', 3),
          (10001,  8001, '温州市机构', 3),
          (10002,  8001, '宁波市机构', 3),
          (10003, 10000, '杭州市西湖区机构', 4),
          (10004, 10003, '杭州市西湖区学院路机构', 5),
          (10005, 'xxx', '安徽省', 2)
      ),
      
      orders(org_id, price) AS (
        VALUES
          (10001, 1.03),
          (10002, 1.32),
          (10003, 3.11),
          (10004, 4.02)
      ),
      
      -- 查询 query.root_name 之下所有地区信息,第一层作为 root_id
      -- (这个例子中,地级市作为 root_id)
      all_areas_under(root_id, org_id, org_name, level) AS (
        SELECT NULL, org.id, org.name, 0
          FROM query
          JOIN org ON org.name = query.root_name
         UNION ALL
        SELECT IFNULL(root_id, org.id), org.id, org.name, level + 1
          FROM all_areas_under a
          JOIN org ON org.parent_id = a.org_id
      )
    
    SELECT org_name '地级市', sum(price) '总收入', MIN(level) '无用列'
      FROM all_areas_under
      LEFT JOIN orders USING(org_id)
     WHERE root_id IS NOT NULL
     GROUP BY root_id;
    
  • @Ta / 2022-10-09 / /

    @无名啊, 这个 统计地级市的时候,需要把 他下面的 县,街道,村,生产队 的订单 都要统计归入到 市

  • @Ta / 2022-10-09 / /

    @胡椒舰长,统计了呀,你瞅瞅 杭州市 的总收入,是不是 7.13

  • @Ta / 2022-10-09 / /

    @胡椒舰长,这是直接几层 JOIN 的例子:

    结果

    地级市 总收入
    杭州市机构 7.13
    温州市机构 1.03
    宁波市机构 1.32

    SQLite 实现

    ... 省略的内容,参考 4 楼)

    WITH
      
      query(root_name) AS (
        VALUES ('浙江省机构')
      ),
      
      org(id, parent_id, name, area_level) AS (...),
      
      orders(org_id, price) AS (...)
    
    SELECT o1.name '地级市',
           IFNULL(p1.price, 0) + IFNULL(p2.price, 0) + IFNULL(p3.price, 0) '总收入'
      FROM query
      JOIN org o0 ON o0.name = query.root_name
      LEFT JOIN org o1 ON o1.parent_id = o0.id
      LEFT JOIN org o2 ON o2.parent_id = o1.id
      LEFT JOIN org o3 ON o3.parent_id = o2.id
      LEFT JOIN orders p1 ON p1.org_id = o1.id
      LEFT JOIN orders p2 ON p2.org_id = o2.id
      LEFT JOIN orders p3 ON p3.org_id = o3.id;
    
  • @Ta / 2022-10-09 / /

    @胡椒舰长,感觉 area_level 是无用列。。(反正我没用到)

  • @Ta / 2022-10-09 / /

    @无名啊,level还是有用的,因为他有一些地方他的parent_ID是杭州的,但是他的level是可能是 4 5 6 7,这些就是杭州市直接管理的,所以他统计的时候还有一个是浙江省直辖
    机构

  • @Ta / 2022-10-09 / /

    @胡椒舰长,噢噢,可能你其他查询有用到吧

    上面那俩能正常工作嘛?

  • @Ta / 2022-10-09 / /

    @无名啊还没呢我中午休息到2:00

  • @Ta / 2022-10-09 / /

    @胡椒舰长,如果你的 org 表很大,且不常更新的话,改成 嵌套集合模型Nested Set Model,也称左右值树),可以加速查询“某地区下的所有地区

    (因为这种树结构只需一次 FROM org WHERE id BETWEEN xxx AND yyy。而你当前的表结构,实际需要 N 次 FROM org WHERE id = ?

  • @Ta / 2022-10-09 / /

    @胡椒舰长,或者,改成 JSON 类型,应该也很快?(就看数据库 json 引擎解析性能了。SQLite 号称 1 GB/s)

添加新回复
回复需要登录