如何使用l-tree计算记录

时间:2018-05-17 19:44:11

标签: sql postgresql

我有两个表,ticketscategoriescategories表格包含3列感兴趣:idnamepath。数据如下所示:

id | Name | Path   
------------------
1  | ABC  | 1
2  | DEF  | 1.2
3  | GHI  | 1.2.3
4  | JKL  | 4
5  | MNO  | 4.5
6  | PQR  | 4.5.6
9  | STU  | 4.5.9

请注意,path列是l-tree。这意味着代表id=2的类别是id=1的子类别,而id=3id=2的子类别。

在我的故障单表格中,有一个名为category_id的列,它引用了我的类别表中的id列。每张票证最多可分配一个类别(category_id可能为空)。

我试图计算每个类别的所有门票。

假设我的票证表如下所示:

ticket_id | ticket_title | category_id
    1     |      A       |    1
    2     |      B       |    2
    3     |      C       |    3
    4     |      D       |    5
    5     |      F       |    5
    6     |      G       |    6
    7     |      H       |    9

我想输出:

category_id | count
    1       |   3
    2       |   2
    3       |   1
    4       |   4
    5       |   4
    6       |   1
    9       |   1

我发现我可以通过以下查询获取属于给定类别的所有门票:select * from tickets where category_id in (select id from categories where path ~ '*.1.*');(虽然现在我正在写这个问题我是' m不相信这是正确的。)

我还试图按类别执行逐个计票的问题,我想出了:

SELECT
 categories.id    as cid,
 COUNT(*)           as tickets_count
FROM tickets
  LEFT JOIN categories ON tickets.category_id = categories.id
GROUP BY cid;

输出以下内容:

c_id | count
 1   |   1
 2   |   1
 3   |   1
 5   |   2
 6   |   1
 9   |   1

我不太擅长SQL。是否有可能实现我想要的目标?

2 个答案:

答案 0 :(得分:1)

你很接近,但你需要一个更通用的-1

join

比较中的SELECT c.id as cid, COUNT(*) as tickets_count FROM categories c LEFT JOIN tickets t ON t.category_id || '.' LIKE c.id || '.%' GROUP BY c.id; 只是因为'.'1.100不匹配。

答案 1 :(得分:1)

试试这个:

WITH tickets_per_path AS (
SELECT
  c.path   AS path,
  count(*) AS count
FROM tickets t INNER JOIN categories c ON (t.category_id = c.id)
GROUP BY c.path) 

SELECT 
 c.id,
 sum(tickets_per_path.count) AS count
FROM categories c LEFT JOIN tickets_per_path ON (c.path @> tickets_per_path.path)
GROUP BY c.id
ORDER BY c.id;

产生以下结果:

id| count
1 | 3
2 | 2
3 | 1
4 | 4
5 | 4
6 | 1
9 | 1

大致如下:

  1. WITH子句计算每个路径的票数(没有 包括后代路径的门票数量。)
  2. 第二个select子句使用预先计算的tickets_per_path视图连接categories表,但不是路径上的equi-join,而是 通过测试左表(类别)中的记录是否为连接 右侧表的祖先(使用@>运算符)。然后呢 按类别ID分组,并按类别汇总票证计数 包括后代计数。