Mysql 具有多个关系的递归查询

Mysql 具有多个关系的递归查询,mysql,sql,common-table-expression,Mysql,Sql,Common Table Expression,表格表示法是对实际问题的简化,因为它捕捉了情况,但更容易理解 两个表包含计量单位的定义。有一个包含所有单位符号的表,还有一个包含所有单位定义段的多个相关表。比如说, 它将码定义为0.9144米 它将链定义为22码 它将furlong定义为220码 它将英亩定义为1chain times1furlong 表: measurement_units id name is_base_unit ---------------------------------- 1

表格表示法是对实际问题的简化,因为它捕捉了情况,但更容易理解

两个表包含计量单位的定义。有一个包含所有单位符号的表,还有一个包含所有单位定义段的多个相关表。比如说,

  • 它将码定义为
    0.9144
  • 它将链定义为
    22
  • 它将furlong定义为
    220
  • 它将英亩定义为
    1
    chain times
    1
    furlong
表:

measurement_units
id      name        is_base_unit
----------------------------------
1       meter       1
2       yard        0
3       chain       0
4       furlong     0
5       acre        0


measurement_unit_derivations
id      measurement_unit_id     derives_from_measurement_unit_id    factor
---------------------------------------------------------------------------
1       2                       1                                   0.9144
2       3                       2                                   22
3       4                       2                                   220
4       5                       3                                   1
5       5                       4                                   1
我试图编写一个递归公共表表达式,其中每个度量单位的比率是相对于相关物理维度的基本单位计算的。例如,结果应包含码与米的比率和英亩与平方米的比率。应该是这样的:

measurement_unit_id     name        ratio
-------------------------------------------
1                       meter       1
2                       yard        0.9144
3                       chain       20.1168
4                       furlong     201.168
5                       acre        4046.8564224
问题是一个单位可以从多个其他单位派生。例如,为了找出一英亩与平方米的比率,我们将看到它来自一个弗隆和一条链,而这反过来又来自其他单位

我未能继续:

WITH RECURSIVE cte AS (
    SELECT 
        id AS measurement_unit_id
        name,
        1 AS ratio
    FROM measurement_units
    WHERE is_base_unit = 1
    UNION ALL
    ???
)
编辑:关于米和英亩的示例表便于描述,但也“太简单”。我创建了另一个递归查询也可以使用的示例:

这个结果就是目标:

measurement_unit_id     name        ratio
-------------------------------------------
1                       A           1
2                       B           1
3                       C           2
4                       D           8
5                       E           16
下面是创建这两个表及其内容的快速而肮脏的SQL

CREATE TABLE `measurement_units` (`id` int(10) UNSIGNED NOT NULL, `name` varchar(190) NOT NULL, `is_base_unit` tinyint(3) UNSIGNED NOT NULL);
CREATE TABLE `measurement_unit_derivations` (`id` int(10) UNSIGNED NOT NULL, `measurement_unit_id` int(10) UNSIGNED NOT NULL, `derived_from_measurement_unit_id` int(10) UNSIGNED NOT NULL, `factor` int(10) UNSIGNED NOT NULL);

INSERT INTO `measurement_units` (`id`, `name`, `is_base_unit`) VALUES (1, 'A', 1), (2, 'B', 1), (3, 'C', 0), (4, 'D', 0), (5, 'E', 0);
INSERT INTO `measurement_unit_derivations` (`id`, `measurement_unit_id`, `derived_from_measurement_unit_id`, `factor`) VALUES (1, 3, 1, 2), (2, 4, 2, 2), (3, 4, 3, 2), (4, 5, 4, 2);

您已正确获得递归种子集。我们从
base\u unit=1
开始。
UNION ALL
之后的下一节是递归项。在这里,您可以引用cte并将其连接到源表,从而为迭代建立关系

递归项的形式如下:

SELECT 
    mu.id,
    mu.name,
    cte.ratio * mud.factor
FROM
    cte
    INNER JOIN measurement_unit_derivations mud
        ON cte.measurement_unit_id = mud.derives_from_measurement_unit_id
    INNER JOIN measurement_units mud
        ON mud.measurement_unit_id = mu.id
这将为从两个或多个维度导出的测量创建多个记录。由于规则似乎是我们将多个衍生测量值相乘,以确定比率(链*furlows=acres),那么我们可以在递归cte完成后进行聚合

诀窍在于没有乘法聚合,就像有加法一样(
SUM()
)。所以我们得算算出来。我相信以下方法会奏效:

SELECT measurement_unit_id, name, EXP(SUM(LOG(ratio))) FROM cte GROUP BY measurement_unit_id, name;
综上所述:

WITH RECURSIVE cte AS (
    SELECT 
        measurement_unit_id
        name,
        1 AS ratio
    FROM measurement_units
    WHERE base_unit = 1
    UNION ALL
    SELECT 
        mu.id,
        mu.name,
        cte.ratio * mud.factor
    FROM
        cte
        INNER JOIN measurement_unit_derivations mud
            ON cte.measurement_unit_id = mud.derives_from_measurement_unit_id
        INNER JOIN measurement_units mud
            ON mud.measurement_unit_id = mu.id
)
SELECT measurement_unit_id, name, EXP(SUM(LOG(ratio))) FROM cte GROUP BY measurement_unit_id, name;

您已正确获得递归种子集。我们从
base\u unit=1
开始。
UNION ALL
之后的下一节是递归项。在这里,您可以引用cte并将其连接到源表,从而为迭代建立关系

递归项的形式如下:

SELECT 
    mu.id,
    mu.name,
    cte.ratio * mud.factor
FROM
    cte
    INNER JOIN measurement_unit_derivations mud
        ON cte.measurement_unit_id = mud.derives_from_measurement_unit_id
    INNER JOIN measurement_units mud
        ON mud.measurement_unit_id = mu.id
这将为从两个或多个维度导出的测量创建多个记录。由于规则似乎是我们将多个衍生测量值相乘,以确定比率(链*furlows=acres),那么我们可以在递归cte完成后进行聚合

诀窍在于没有乘法聚合,就像有加法一样(
SUM()
)。所以我们得算算出来。我相信以下方法会奏效:

SELECT measurement_unit_id, name, EXP(SUM(LOG(ratio))) FROM cte GROUP BY measurement_unit_id, name;
综上所述:

WITH RECURSIVE cte AS (
    SELECT 
        measurement_unit_id
        name,
        1 AS ratio
    FROM measurement_units
    WHERE base_unit = 1
    UNION ALL
    SELECT 
        mu.id,
        mu.name,
        cte.ratio * mud.factor
    FROM
        cte
        INNER JOIN measurement_unit_derivations mud
            ON cte.measurement_unit_id = mud.derives_from_measurement_unit_id
        INNER JOIN measurement_units mud
            ON mud.measurement_unit_id = mu.id
)
SELECT measurement_unit_id, name, EXP(SUM(LOG(ratio))) FROM cte GROUP BY measurement_unit_id, name;

如何用这些数字计算英亩数。一个人如何知道(对这些测量的尺寸一无所知)一个人是多个链条和分叉的?是不是如果它“衍生”于多个测量值,那么这些测量值将被乘以以确定结果?@jnevil是的,你的假设是正确的。我也没有在这些示例表中包含关于物理维度的信息,因为它在查询中不起作用。如何使用这些数字计算Acre。一个人如何知道(对这些测量的尺寸一无所知)一个人是多个链条和分叉的?是不是如果它“衍生”于多个测量值,那么这些测量值将被乘以以确定结果?@jnevil是的,你的假设是正确的。我也没有在这些示例表中包含有关物理维度的信息,因为它在查询中不起作用。EXP(SUM(LOG(expression))是计算组乘积的好方法,因为我们只处理大于0的值。然而,我认为当派生不像我最初的示例中那样彼此“平行”时,您的解决方案不起作用。我在edit中添加了另一个虚构度量单位的示例。EXP(SUM(LOG(expression))是计算组乘积的好方法,因为我们只处理大于0的值。然而,我认为当派生不像我最初的示例中那样彼此“平行”时,您的解决方案不起作用。我在编辑中添加了另一个虚构度量单位的示例。