Имея идентификатор вложенного элемента и идентификатор владельца, узнайте, принадлежит ли элемент этому владельцу - PullRequest
1 голос
/ 16 июня 2020

Эта таблица называется категорией:

id|template_id|name    |entry_count|is_base_template|can_rename|can_delete|section|userId|parentCategoryId|
--|-----------|--------|-----------|----------------|----------|----------|-------|------|----------------|
 1|           |ToDo    |          0|true            |true      |true      |A      |      |                |
 2|           |Notes   |          0|true            |true      |true      |A      |      |                |
 3|          1|ToDo    |          0|false           |true      |true      |A      |     1|                |
 4|          2|Notes   |          0|false           |true      |true      |A      |     1|                |
 5|           |my todos|          0|false           |          |          |A      |      |               3|
 6|          1|ToDo    |          0|false           |true      |true      |A      |     2|                |
 7|          2|Notes   |          0|false           |true      |true      |A      |     2|                |

Каждая категория может иметь дочерние элементы, можно определить, имеем ли мы дело с категорией или подкатегорией, по полю с именем parentCategoryId, это NULL для категорий и не NULL для подкатегорий.

Я знаю userId и идентификатор категории, который в этой таблице просто id. Мне нужно выяснить, принадлежит ли категория с определенным идентификатором (например, id = 5) определенному пользователю (например, с id = 1).

Для этого должен быть какой-то трюк, но я могу Не думаю об одном.

Моя версия PostgreSQL - 12.3.

EDIT-1 :

Прежде всего, спасибо .

Я попытался запустить его в моем локальном клиенте (DBeaver), а также в консоли, и он не работал. Я только что изменил демонстрацию на категорию:

WITH RECURSIVE cte AS (
    SELECT id, userId, parentCategoryId
    FROM category
    WHERE id = 5 --the category of interest

    UNION

    SELECT d.id, d.userId, d."parentCategoryId"
    FROM category d
             INNER JOIN cte ON d.id = cte."parentCategoryId"
)
SELECT TRUE
FROM cte
WHERE userId = 1 --the user of interest
LIMIT 1;

Я получаю сообщение об ошибке:

SQL Error [42703]: ERROR: column "userid" does not exist
  Hint: Perhaps you meant to reference the column "category.userId".
  Position: 40

EDIT-2 :

Если я выключу эту строку

SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = 'category';

Результат, который я получаю, выглядит так:

column_name     |
----------------|
parentCategoryId|
template_id     |
userId          |
id              |
entry_count     |
is_base_template|
can_rename      |
can_delete      |
name            |
section         |

1 Ответ

1 голос
/ 16 июня 2020

Демо-данные:

CREATE TABLE category
(
    "id"               INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY,
    "name"             TEXT    NOT NULL,
    "userId"           INTEGER NULL,
    "parentCategoryId" INTEGER NULL,

    CONSTRAINT category_pkey PRIMARY KEY (id),
    CONSTRAINT cateory_fkey_parent_id FOREIGN KEY ("parentCategoryId") REFERENCES category (id)
);

INSERT INTO category(name, "userId", "parentCategoryId")
VALUES ('ToDo', NULL, NULL);
INSERT INTO category(name, "userId", "parentCategoryId")
VALUES ('Notes', NULL, NULL);
INSERT INTO category(name, "userId", "parentCategoryId")
VALUES ('ToDo', 1, NULL);
INSERT INTO category(name, "userId", "parentCategoryId")
VALUES ('Notes', 1, NULL);
INSERT INTO category(name, "userId", "parentCategoryId")
VALUES ('my_todos', NULL, 3);
INSERT INTO category(name, "userId", "parentCategoryId")
VALUES ('ToDo', 2, NULL);
INSERT INTO category(name, "userId", "parentCategoryId")
VALUES ('Notes', 2, NULL);

Вы можете использовать рекурсивный запрос, чтобы найти родительское дерево вашей категории, затем вы можете проверить, владеет ли пользователь каким-либо из родительских узлов:

WITH RECURSIVE cte AS (
    SELECT "id", "userId", "parentCategoryId"
    FROM category
    WHERE id = 5 --the category of interest

    UNION

    SELECT d."id", d."userId", d."parentCategoryId"
    FROM category d
             INNER JOIN cte ON d."id" = cte."parentCategoryId"
)
SELECT TRUE
FROM cte
WHERE "userId" = 1 --the user of interest
LIMIT 1;

Обратите внимание, что все имена столбцов заключены в кавычки - это означает, что они чувствительны к регистру.

Как работает запрос:

Рекурсивный запрос содержит части дерева:

  1. База запроса (нерекурсивная), которая извлекает некоторые rows

  2. Предложение UNION, которое объединяет результаты рекурсивной и нерекурсивной частей

  3. Рекурсивная часть, которая выполняется для каждой строки возвращается как из рекурсивной, так и из нерекурсивной частей.

В ваших данных примера база запроса возвращает строку (id=5, user=null, parentCategoryId=3). Эта строка передается в качестве входных данных для рекурсивного запроса, который объединяет ее с таблицей category. Другой запрос возвращает новую строку (id=3, userId=1, parentCategoryId=null). Эта строка снова передается в качестве аргумента рекурсивному запросу, но как parentCategoryId=null, на этот раз запрос не возвращает никаких строк, и в результате выполнение прекращается. Предложение UNION объединяет две строки в один набор результатов. Теперь внешний select проверяет, содержит ли какая-либо из возвращенных строк userId=1, и в этом случае возвращает TRUE.

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