Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
单亲子表中层次数据的MySQL乘法_Mysql_Hierarchical Data - Fatal编程技术网

单亲子表中层次数据的MySQL乘法

单亲子表中层次数据的MySQL乘法,mysql,hierarchical-data,Mysql,Hierarchical Data,我正在从事一个项目,其MySQL数据库包含两个表;人员和百分比 人员表: +----+------+--------+ | ID | Name | Parent | +----+------+--------+ | 1 | A | 0 | | 2 | B | 1 | | 3 | C | 2 | | 4 | D | 3 | | 5 | E | 1 | | 6 | F | 0 | +----+

我正在从事一个项目,其MySQL数据库包含两个表;人员和百分比

人员表:

+----+------+--------+ | ID | Name | Parent | +----+------+--------+ | 1 | A | 0 | | 2 | B | 1 | | 3 | C | 2 | | 4 | D | 3 | | 5 | E | 1 | | 6 | F | 0 | +----+------+--------+ 百分比表:

+----+------------+ | ID | Percentage | +----+------------+ | 1 | 70% | | 2 | 60% | | 3 | 10% | | 4 | 5% | | 5 | 40% | | 6 | 30% | +----+------------+ 我正在查找的查询结果应如下所示:

+----+------------+----------------+--------+ | ID | Percentage | Calculation | Actual | +----+------------+----------------+--------+ | 1 | 70 | 70% | 70.00% | | 2 | 60 | 70%*60% | 42.00% | | 3 | 10 | 70%*60%*10% | 4.20% | | 4 | 5 | 70%*60%*10%*5% | 0.21% | | 5 | 40 | 70%*40% | 28.00% | | 6 | 30 | 30% | 30.00% | +----+------------+----------------+--------+
“计算”列仅用于详细说明。有什么MySQL技术可以用来实现这种分层查询吗?即使百分比表可能包含多个条目,同一个人的百分比?

解决方案是利用以下链接中描述的函数进行存档查询:

但是,您需要计算乘法,而不是创建路径

解决方案脚本 直接复制并粘贴到mysql控制台中。我在工作台上运气不太好。此外,这可以通过将hierarchy_sys_connect_by_path_percentage和hierarchy_sys_connect_by_path_percentage_结果组合到一个存储过程中来进一步优化。不幸的是,对于大型数据集来说,这可能相当缓慢

设置表和数据 结果

格式化数字很简单,所以我把它留给你。。。 更重要的是优化以减少对数据库的调用。

MySQL是一种关系数据库。您的需求需要一个新的解决方案


但是,如果您继续使用MySQL,则有一些方法可以添加一些图形特性。其中一个是概念。但我不建议这样做,因为这会增加很多复杂性。

步骤1-创建一个MySQL函数,以将族谱作为逗号分隔的文本列返回:

SELECT a.id
     , ROUND(pa.percentage/100
     * COALESCE(pb.percentage/100,1)
     * COALESCE(pc.percentage/100,1)
     * COALESCE(pd.percentage/100,1) 
     * 100,2) x
  FROM people a 
  LEFT 
  JOIN people b 
    ON b.id = a.parent 
  LEFT 
  JOIN people c 
    ON c.id = b.parent 
  LEFT 
  JOIN people d 
    ON d.id = c.parent
  LEFT
  JOIN percentages pa
    ON pa.id = a.id
  LEFT
  JOIN percentages pb
    ON pb.id = b.id
  LEFT
  JOIN percentages pc
    ON pc.id = c.id
  LEFT
  JOIN percentages pd
    ON pd.id = d.id
;
DELIMITER //

CREATE FUNCTION fnFamilyTree ( id INT ) RETURNS TEXT
BEGIN
   SET @tree = id;
   SET @qid = id;
   WHILE (@qid > 0) DO
      SELECT IFNULL(p.parent,-1)
        INTO @qid
        FROM people p
       WHERE p.id = @qid LIMIT 1;
      IF ( @qid > 0 ) THEN
        SET @tree = CONCAT(@tree,',',@qid);
      END IF;
   END WHILE;
   RETURN @tree;
END
//

DELIMITER ;
然后使用以下SQL检索结果:

SELECT ppl.id
      ,ppl.percentage
      ,GROUP_CONCAT(pct.percentage SEPARATOR '*') as Calculations
      ,EXP(SUM(LOG(pct.percentage)))              as Actual
  FROM (SELECT p1.id
              ,p2.percentage
              ,fnFamilyTree( p1.id ) as FamilyTree
          FROM people      p1
          JOIN percentages p2
            ON p2.id = p1.id
       ) ppl
  JOIN percentages pct
    ON FIND_IN_SET( pct.id, ppl.FamilyTree ) > 0
 GROUP BY ppl.id
         ,ppl.percentage
;
摆弄

结果:

+------+----------------+-----------------+----------------+
| ID   | Percentage     | Calculations    | Actual         |
+------+----------------+-----------------+----------------+
| 1    | 0.699999988079 | 0.7             | 0.699999988079 |
| 2    | 0.600000023842 | 0.7*0.6         | 0.420000009537 |
| 3    | 0.10000000149  | 0.7*0.6*0.1     | 0.04200000158  |
| 4    | 0.5            | 0.1*0.5*0.7*0.6 | 0.02100000079  |
| 5    | 0.40000000596  | 0.4*0.7         | 0.279999999404 |
| 6    | 0.300000011921 | 0.3             | 0.300000011921 |
+------+----------------+-----------------+----------------+

考虑切换到Postgres9,它支持:


查看demo

您想要计算结果吗?MySQL对分层数据结构的支持非常糟糕。或者您需要编写一个存储过程。或者,您可以修改数据结构以包含根目录的整个路径,而不仅仅是父目录。@Gordon Linoff您完全抓住了问题的关键!或者尽可能频繁地将表连接到自身,或者在应用程序级别处理递归,或者切换到嵌套集模型。@Gordon这是因为它不必这样做。抱怨关系数据库上缺少图形功能与抱怨铺砌公路上的KTM是一样的。+1,因为这扩展了具有所需图形功能的表,并适度增加了复杂性。连接两个表将始终生成由多行错误组成的结果。有什么建议吗?它非常有效,但只有在百分比表上的ID列是唯一的情况下才有效。当行为作为外键值开始在多行上重复时,由多行组成的结果错误开始出现。为什么一个id有多个百分比?根据你的设计没有意义。不,在这种情况下没有意义。我正在用这个简单的案例模拟一个更复杂的场景。在实际场景中,每个人都有多个帐户,而这些帐户又有相应的比率。账户之间通过百分比进行交互。简言之,人们通过id与账户相关,账户通过账户id与RatioPercentage相关,账户id可以是贷方+或借方-。因此,计算应该通过人们的账户,并通过三个表中每个表的键进行。类似于将百分比视为对外关系。我知道这是一个头疼的问题。虽然知道Postgres可以处理这件事很好,但切换到其他数据库并不是一件小事,因此不是一个可行的解决方案。非常好!我特别喜欢通过对数加法进行乘法运算,这是我在数据库中从未考虑过的!!
DELIMITER //

CREATE FUNCTION fnFamilyTree ( id INT ) RETURNS TEXT
BEGIN
   SET @tree = id;
   SET @qid = id;
   WHILE (@qid > 0) DO
      SELECT IFNULL(p.parent,-1)
        INTO @qid
        FROM people p
       WHERE p.id = @qid LIMIT 1;
      IF ( @qid > 0 ) THEN
        SET @tree = CONCAT(@tree,',',@qid);
      END IF;
   END WHILE;
   RETURN @tree;
END
//

DELIMITER ;
SELECT ppl.id
      ,ppl.percentage
      ,GROUP_CONCAT(pct.percentage SEPARATOR '*') as Calculations
      ,EXP(SUM(LOG(pct.percentage)))              as Actual
  FROM (SELECT p1.id
              ,p2.percentage
              ,fnFamilyTree( p1.id ) as FamilyTree
          FROM people      p1
          JOIN percentages p2
            ON p2.id = p1.id
       ) ppl
  JOIN percentages pct
    ON FIND_IN_SET( pct.id, ppl.FamilyTree ) > 0
 GROUP BY ppl.id
         ,ppl.percentage
;
+------+----------------+-----------------+----------------+
| ID   | Percentage     | Calculations    | Actual         |
+------+----------------+-----------------+----------------+
| 1    | 0.699999988079 | 0.7             | 0.699999988079 |
| 2    | 0.600000023842 | 0.7*0.6         | 0.420000009537 |
| 3    | 0.10000000149  | 0.7*0.6*0.1     | 0.04200000158  |
| 4    | 0.5            | 0.1*0.5*0.7*0.6 | 0.02100000079  |
| 5    | 0.40000000596  | 0.4*0.7         | 0.279999999404 |
| 6    | 0.300000011921 | 0.3             | 0.300000011921 |
+------+----------------+-----------------+----------------+
WITH RECURSIVE recp AS (
SELECT p.id, p.name, p.parent
, array[p.id] AS anti_loop
, array[pr.percentage ] AS percentages
, pr.percentage AS final_pr
FROM people p
JOIN percentages pr ON pr.id = p.id
WHERE parent = 0
UNION ALL
SELECT ptree.id, ptree.name, ptree.parent
, recp.anti_loop || ptree.id
, recp.percentages || pr.percentage
, recp.final_pr * pr.percentage
FROM people ptree
JOIN percentages pr ON pr.id = ptree.id
JOIN recp ON recp.id = ptree.parent AND ptree.id != ALL(recp.anti_loop)
)
SELECT id, name
, array_to_string(anti_loop, ' <- ') AS path
, array_to_string(percentages::numeric(10,2)[], ' * ') AS percentages_str
, final_pr
FROM recp
ORDER BY anti_loop