Как представлять данные при работе с несколькими вложенными объединениями и отношениями 1: M / M: 1? - PullRequest
0 голосов
/ 29 января 2020

Я сделал DB-Fiddle этой проблемы, чтобы его было легче читать: https://www.db-fiddle.com/f/iwGtTkgBpAtsohFuAG2A4L/2

С учетом следующей схемы:

-- Table that holds the data of a Character.
CREATE TABLE Character (
  id SERIAL,
  name TEXT,
  description TEXT,

  PRIMARY KEY (id)
);

-- 1:M relationship between Character -> CharacterSkill, one Character can have multiple skills.
CREATE TABLE CharacterSkill (
  id SERIAL,
  character INTEGER,
  name TEXT,
  description TEXT,
  value_1 INTEGER,

  PRIMARY KEY (id),
  FOREIGN KEY (character) REFERENCES Character (id)
);

-- 1:M relationship between CharacterSkill -> CharacterSkillItems. One skill might require one or more items to level up.
CREATE TABLE CharacterSkillItems (
  id SERIAL,
  skill_id INTEGER,
  item_id INTEGER, --references to another table that is going to be joined for the item name. For sake of length I don't add it.
  amount INTEGER,

  PRIMARY KEY (id),
  FOREIGN KEY (skill_id) REFERENCES CharacterSkill (id)
  --FOREIGN KEY (item_id) REFERENCES Item (id)
);

С следующие тестовые данные:

-- Adding a character to the database.
INSERT INTO Character (name, description) VALUES ('Character 1', 'Character 1 Description');

-- Adding the skills of that character. They have two.
INSERT INTO CharacterSkill (character, name, description, value_1) VALUES (1, 'Character 1 Skill 1', 'Character 1 Skill 1 Description', 5);
INSERT INTO CharacterSkill (character, name, description, value_1) VALUES (1, 'Character 1 Skill 2', 'Character 1 Skill 2 Description', 50);

-- First skill requires 2 items to level up.
INSERT INTO CharacterSkillItems (skill_id, item_id, amount) VALUES (1, 10, 5);
INSERT INTO CharacterSkillItems (skill_id, item_id, amount) VALUES (1, 10, 5);

-- Second skill requires 3 items to level up.
INSERT INTO CharacterSkillItems (skill_id, item_id, amount) VALUES (2, 10, 10);
INSERT INTO CharacterSkillItems (skill_id, item_id, amount) VALUES (2, 20, 5);
INSERT INTO CharacterSkillItems (skill_id, item_id, amount) VALUES (2, 40, 5);

Каков наилучший подход к извлечению данных персонажа со всеми его навыками и необходимыми предметами (для этого потребуется еще одно СОЕДИНЕНИЕ для имен предметов) * Только 1013 * для представления данных? Один из подходов, который я могу придумать, состоит в том, чтобы разделить это на несколько запросов, но из того, что я исследовал, можно ли справиться с этим в одном запросе, лучше оставить его в одном запросе, поэтому, если бы мне пришлось оставить его только в одном запросе Я думал об использовании json_agg с json_build_object, но это, кажется, становится неприятным, так как я продолжаю углубляться в плане вложенных запросов и при работе с несколькими навыками / предметами.

РЕДАКТИРОВАТЬ: Я обновил базу данных -Поддержать мою попытку построить его, используя json методы. Это работает, но, как я уже упоминал ранее, чем глубже я продолжаю работать с JOINs, тем хуже это выглядит. Я не уверен, есть ли лучший способ справиться с этим.

Запрос в вопросе:

SELECT 
  char.name, 
  char.description,
  skills.skill_list 
FROM 
  Character char 
  JOIN (
    SELECT 
      skill.character, 
      json_agg(
        json_build_object(
          'name', skill.name, 'description', 
          skill.description, 'value_1', skill.value_1,
          'costs', cost_list.costs
        )
      ) AS "skill_list" 
    FROM 
      CharacterSkill skill 
      JOIN (
        SELECT 
          skill_id, 
          json_agg(
            json_build_object(
              'item_id', item_id, 'amount', amount
            )
          ) AS "costs" 
        FROM 
          SkillUpgradeItem 
        GROUP BY 
          skill_id
      ) cost_list ON skill.id = cost_list.skill_id 
    GROUP BY 
      character
  ) skills ON skills.character = char.id;
...