Как считать записи, используя l-дерево - PullRequest
0 голосов
/ 17 мая 2018

У меня есть две таблицы, tickets и categories.Таблица categories имеет 3 интересующих столбца: id, name и path.Данные выглядят так:

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=3 является подкатегорией id=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.*'); (хотя сейчас, когда я пишу этот вопрос, я не уверен, что это правильно).

Я также попытался выполнить тикетпроблема подсчета по категориям, и я придумал:

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 голосов
/ 18 мая 2018

Попробуйте это:

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, но вместо равного соединения на пути оно присоединяетсяпроверка, является ли запись в левой таблице (категориях) предком правой таблицы (с помощью оператора @>).Затем он группируется по идентификатору категории и суммирует количество билетов по категориям, включая количество потомков.
0 голосов
/ 17 мая 2018

Вы близки, но вам нужен более общий 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...