sql - 在一对多系统中存储和计算关系

标签 sql algorithm logic one-to-many

我正在抓耳挠腮,寻找实现这一目标的合理方法。标题真的很难理解,所以如果你进入这篇文章是希望得到别的东西,我很抱歉。这既是一个数据库问题,也是一个逻辑问题。

我在一个“集合”中有 100 个条目。让我们称每一个为对象。每个对象都引用数据库中的一个条目,并有一些名称(比如 obj1、obj2 ...)。其中一些对象是其他对象的“复合体”。因此,例如,如果 obj1 和 obj2 是输入,则 obj11 是输出 (obj1, obj2 -> obj11)。甚至可能是同一对象的多个输入:obj1 x 4、obj2、obj11 -> obj21。

我正在寻找一种在更改输入的同时连续计算结果对象的方法,因此这些关系必须以某种巧妙的方式存储在数据库中,这样才能以相当优雅的方式完成这样的计算时尚。

自然而然地,我想到了一个多对一的表,但找不到一种合乎逻辑的方法来在不解析整个表的情况下找到给定输入的结果。

有没有人对此有一些想法?

最佳答案

您似乎在构建一种食谱系统。一些对象是由不同数量的其他对象创建的。在数据结构方面,你可以有类似的东西

   struct Thing {
     std::vector<Ingredient> parts;
     // ... other attributes here
   };

   struct Ingredient {
     Thing component;
     int count;
   };

这可以使用

存储
   CREATE TABLE `Things` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
       # ... other attributes here
      PRIMARY KEY `id`
   );

   CREATE TABLE `Ingredients` (
      `id` int(11) NOT NULL AUTO_INCREMENT,           
      `result_id` int(11) NOT NULL,
      `component_id` int(11) NOT NULL, 
      `count` int(11) NOT NULL,
       PRIMARY KEY `id`
   );

   ALTER TABLE `Ingredients` FOREIGN KEY (`result_id`) REFERENCES `Thing` (`id`);
   ALTER TABLE `Ingredients` FOREIGN KEY (`component_id`) REFERENCES `Thing` (`id`);

存储 Thing 的配方,只需将其所有成分及其数量作为配料插入即可。要检索食谱,只需 SELECT所有成分result_id .看看哪里有Thing在配方中使用,只需查询它作为组件的用途。

想象一下 AB 构建和 C ;那B可以从 D 构建和 E .然后你可能想要执行多阶段查询,从A中找出= B + CA = ( D + E ) + C .这需要对每个组件进行额外选择,以查看它本身是否具有成分。但是,除非您的食谱形成一棵树,否则这会适得其反:如果A怎么办?需要 BB可以从 A 构建?。更糟糕的是:如果有几种方法可以获得 A 怎么办? , 比如说来自 B + C或来自 X + Y ?如果您需要区分这些替代食谱,您将需要一个额外的表格:

   struct Thing {
     std::vector<Recipe> recipes;
     // ... other attributes here
   };

   struct Recipe {
     std::vector<Ingredient> ingredients;
     // ... other attributes here
   };

   struct Ingredient {
     Thing component;
     int count;
   };

并且,在 SQL 中,

   CREATE TABLE `Recipes` (
      `id` int(11) NOT NULL AUTO_INCREMENT,           
      `result_id` int(11) NOT NULL, 
      PRIMARY KEY `id`
   );

   CREATE TABLE `Ingredients` (
      `id` int(11) NOT NULL AUTO_INCREMENT,           
      `recipe_id` int(11) NOT NULL, 
      `component_id` int(11) NOT NULL, 
      `count` int(11) NOT NULL,
      PRIMARY KEY `id`
   );

   ALTER TABLE `Recipes` FOREIGN KEY (`result_id`) REFERENCES `Thing` (`id`);
   ALTER TABLE `Ingredients` FOREIGN KEY (`recipe_id`) REFERENCES `Recipe` (`id`);
   ALTER TABLE `Ingredients` FOREIGN KEY (`component_id`) REFERENCES `Thing` (`id`);      

如果您需要恢复类似这样的多阶段配方,那么您正在尝试在关系数据库上执行图查询,并且可能会发现使用专为那些对象设计的对象图数据库要容易得多查询类型。


编辑:假设没有循环,每个 Thing 最多 1 个配方,我如何根据配料表找到要 cooking 的食物?有几种方法是可能的。

  • 如果菜谱的数量不是很大,并且菜谱不经常更改,只需将它们全部加载到内存中并使用集合交集来检测可能的菜谱。这将比使用数据库更快。
  • 如果你坚持使用数据库,这行得通(你可以 test it online :
SELECT possible.id 
    FROM (
        SELECT i.result_id AS id, COUNT(*) AS total
        FROM `Ingredients` AS i GROUP BY i.result_id
    ) AS possible, (
        SELECT result_id, COUNT(result_id) AS total
        FROM `Ingredients` AS i WHERE 
            (i.component_id = 1 AND i.count<=1) OR
            (i.component_id = 2 AND i.count<=3) OR
            (i.component_id = 42 AND i.count<=1)
        GROUP BY i.result_id
    ) AS valid
    WHERE possible.id = valid.result_id AND possible.total = valid.total;

关于sql - 在一对多系统中存储和计算关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56902304/

相关文章:

python - 棋盘覆盖递归算法背后的直觉是什么?如何更好地制定这种算法?

c - 填充二维数组的逻辑

SQL Server 创建动态列 Login1、Login2、Login3

c# - 以编程方式通过 LAN 将数据从一台 SQL Server 复制到另一台 SQL Server

sql - 如何连接表,以便右表值取决于左表中的两个不同行

arrays - 找到多种方法可以产生相等的总和?

java - 原生查询导致空指针异常

algorithm - 为什么 clojure 中的并行 qsort 比 common 的实现慢?

java - 丰富矩阵与非丰富矩阵

java - 如何为 Prime Checker [Java] 提供更多的进入和返回因素?