GROUP CONCAT 和 LEFT OUTER JOIN 拆分

GROUP CONCAT and LEFT OUTER JOIN to split

我正在与 SQL Workbench 合作。这是我的表格示例:

SITES
id

BUILDINGS
id
site_id

LEVELS
id
building_id

我没有创建这个数据库,也不能修改它。每个建筑物对应一个站点,因此它包含该站点的 KEY。与关卡和建筑物相同。

我正在尝试得到这个结果

site_id   |   buildings_id   |   levels_id
1         |   15, 16         |   (213, 214), (313, 314)
2         |   21, 22, 23     |   (350), (400, 401, 402), (501)
3         |   31, 32, 33, 34 |   (5001, 5002), (7001), (8009), (8400)

前两列很简单,但我对第三列有疑问。括号是说明性的,我不一定需要那些。但我需要一种方法将字符串拆分为 building_id.

每个 (...) 对应一栋建筑物的楼层。

这是我现在正在处理的查询,return是第一列和第二列。我尝试向查询中添加另一个 LEFT OUTER JOIN,但没有成功。我尝试了很多东西,但我尝试的大多数东西 return 错误或奇怪的输出。

SELECT 
    sites.id AS site_id,
    GROUP_CONCAT(DISTINCT buildings.id
        SEPARATOR '; ') AS buildings_id
FROM
    sites
        LEFT OUTER JOIN
    users_has_sites ON users_has_sites.sites_id = sites.id
        LEFT OUTER JOIN
    users ON users.id = users_has_sites.users_id
        LEFT OUTER JOIN
    buildings ON buildings.sites_id = sites.id
WHERE
    users.id = 42
GROUP BY site_id;

感谢任何帮助。谢谢

根据您的要求和table结构推断 你可以试试这个 sql

SELECT site.id,GROUP_CONCAT(c.building_id) building_id,GROUP_CONCAT(c.level_id) levels_id 从网站,( SELECT building.site_id,building.id building_id, concat('(',GROUP_CONCAT(level.id),')') level_id 来自大楼,level WHERE building.id = level.building_id GROUP BY building.id ) c 其中 site.id = c.site_id 分组 site.id;

您需要两个聚合级别:一个是 building_id,另一个是 site_id

with b_l as (
  select
    b.id as building_id
    , b.site_id
    , concat('('
      , group_concat(
          l.id
          order by l.id
          separator ','
        )
      , ')'
    ) as building_levels
  from buildings as b
    left join levels as l
      on b.id = l.building_id
  group by b.id, b.site_id
)
, s_b as (
  select
    s.id
    , group_concat(
        b_l.building_id
        order by b_l.building_id
        separator ','
      ) as buildings
    , group_concat(
        b_l.building_levels
        order by b_l.building_id
        separator ','
      ) as levels
  from sites as s
    left join b_l
      on s.id = b_l.site_id
  group by s.id
)
select *
from s_b
id | buildings | levels                 
-: | :-------- | :----------------------
 1 | 1,2,3     | (1,2),(3,4,5),(6)      
 2 | 4,5,6     | (7,8),(9),(10,11)      
 3 | 7,8,9     | (12,13,14),(15,16),(17)
 4 | 10        | null                   

或与横向连接相同:

select
  s.id
  , group_concat(
      b_l.building_id
      order by b_l.building_id
      separator ','
    ) as buildings
  , group_concat(
      b_l.building_levels
      order by b_l.building_id
      separator ','
    ) as levels
from sites as s
  left join lateral (
    select
      b.site_id
      , b.id as building_id
      , concat('('
          , group_concat(
              l.id
              order by l.id
              separator ','
            )
          , ')'
        ) as building_levels
    from buildings as b
      left join levels as l
        on b.id = l.building_id
    group by b.id, b.site_id
  ) b_l
    on s.id = b_l.site_id
group by s.id

db<>fiddle here

您可以使用两个级别的聚合,从最低级别开始:

SELECT site_id,
       GROUP_CONCAT(building_id ORDER BY building_id SEPARATOR ', ') as building_ids,
       GROUP_CONCAT('(', levels, ')' ORDER BY building_id SEPARATOR ', ') as levels
FROM (SELECT s.id AS site_id, b.id as building_id,
             GROUP_CONCAT(l.id ORDER BY l.id SEPARATOR ', ') as levels
      FROM sites s LEFT JOIN
           users_has_sites uhs
           ON uhs.sites_id = s.id LEFT JOIN
           buildings b
           ON b.sites_id = s.id LEFT JOIN
           levels l
           ON l.building_id = b.id
      WHERE uhs.users_id = 42
      GROUP BY site_id, b.id
     ) sb
GROUP BY site_id;

请注意,users table 不是必需的,因为 id 在联结点 table 中。此外,可能不需要 sites 但您将其用于 LEFT JOIN(尽管 WHERE 子句将其转换为 INNER JOIN)。不过我把它留在里面了。