SQL Выберите все узлы в трехуровневом дереве, которые соответствуют критерию - PullRequest
0 голосов
/ 06 января 2019

У меня есть модель PostgreSQL (созданная в контексте Django), которая выглядит примерно так:

CREATE TABLE org (
  id INTEGER NOT NULL,
  parent_id INTEGER,
  name CHARACTER VARYING(24),
  org_type  CHARACTER VARYING(8),
  country CHARACTER VARYING(2)
)

CREATE TABLE rate (
  id INTEGER NOT NULL,
  org_id INTEGER NOT NULL,
  rate DOUBLE PRECISION NOT NULL,
  currency CHARACTER VARYING(3)
)

где org_type является одним из "group", "company" и "branch". У каждого филиала есть компания, и только группы принадлежат группе. Учитывая произвольную компанию или филиал и страну, мне нужно найти все тарифы, для которых org_id - это компания и филиал, принадлежащие к той же группе и находящиеся в указанной стране. Таким образом, на следующей диаграмме для компании 123 (в Канаде) или филиала 124 (в Торонто) при поиске тарифов со страной = "США" будут найдены тарифы, принадлежащие компаниям или филиалам, в поле с надписью "Выбрано":

enter image description here

Я пытаюсь что-то вроде следующего для компаний, где $1 - код страны, а $2 - идентификатор организации:

SELECT rate.org_id, rate.rate, rate.currency
FROM rate, org
WHERE (
  org.country = $1 AND
  rate.org_id=org.id AND
  org.parent_id = $2
) OR (
  ...

и затем я застреваю, пытаясь выяснить, как попросить филиалы, принадлежащие одной из компаний, которые я только что нашел. Я действительно предпочел бы одно большое предложение WHERE, которое вводит все тарифы любой соответствующей организации, чтобы мне не приходилось забивать БД целой кучей запросов.

Редактировать

Основываясь на ответе lau , я попробовал пример ( скрипта SQL ), но это только возвратные ставки для организации, с которой я начинаю.

Ответы [ 2 ]

0 голосов
/ 06 января 2019

Вы можете:

  1. Примените критерии к org так же, как вы
  2. Просматривайте все пути вверх / вниз , используя начальные org (s) в качестве начальной точки
  3. Объедините 2 комплекта с UNION
  4. JOIN со ставками (ниже я сделал LEFT OUTER JOIN, чтобы прояснить, что именно входит в рекурсию).

Пример:

WITH RECURSIVE SelectedOrg AS (
    SELECT * FROM org WHERE id = 4
),
BrowseOrg AS (
    SELECT 1 AS Direction, * FROM SelectedOrg
    UNION ALL
    SELECT -1, * FROM SelectedOrg
    UNION ALL
    SELECT Direction, org.* FROM org JOIN BrowseOrg ON (direction = 1 and org.parent_id = BrowseOrg.id) OR (direction = -1 and org.id = BrowseOrg.parent_id)
)
SELECT DISTINCT rates.id, BrowseOrg.id, rates.rate FROM BrowseOrg LEFT OUTER JOIN rates ON org_id = BrowseOrg.id

Это будет достаточно гибко для обработки случаев, когда вы не знаете, какой уровень org вы выбрали (группа, компания или филиал).
В будущем это также должно быть в состоянии справиться с более глубокой иерархией (если вы когда-нибудь добавите к ней уровни).

0 голосов
/ 06 января 2019

Вы можете сделать это в 2 запроса с некоторым подзапросом.

Пусть company_org_ids = select id from org where country code = $1 and parent_id = $2

Select distinct rate.* from rate where orgid in ($3) or where orgid in (select id from org where parent_id in $3 and country_code =$1)

Здесь $ 3 - это company_org_ids результат первого запроса.

Также это можно сделать одним запросом, заменив переменную $3 первым запросом.

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