从多对多关系中获取数据

Posted

技术标签:

【中文标题】从多对多关系中获取数据【英文标题】:Fetching data from many to many relationship 【发布时间】:2021-08-20 00:21:15 【问题描述】:

我有 3 张桌子

category case cost
office_id
category_id linked to > category_id
case_number linked to > case_number
total_cost

问题: 我需要获取类别表中每个办公室 ID 的案例总数及其各自的成本

我写的查询:

select cm_c_d.case_number,cm_c.office_id,count(*) as case_count from categories as cm_c 
join case as cm_c_d on cm_c.category_id = cm_c_d.category_id 
join cost on cm_c_d.case_number = cost.case_number group by office_id;

但我认为这不会提供所需的结果,因为加入所有三个表会增加行数。

更新的 SQL 查询:

select cm_c.office_id
     , count(DISTINCT cm_costs.case_number) as case_count
     , SUM(total_charge) AS overall_cost
  from cm_categories as cm_c
  JOIN cm_case_details as cm_c_d
    on cm_c.category_id = cm_c_d.category_id
  join cm_costs
    on cm_c_d.case_number = cm_costs.case_number
 group by cm_c.office_id
;

【问题讨论】:

我认为您还没有测试过查询,但如果您测试过,您确定可以使用名为CASE 的表而不用反引号括起来吗?据我所知CASE 是reserved word in mysql,在MySQL 查询中使用它而不用反引号将返回错误:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'case' 如果您更新我提供的插入语句(用于导致问题的特殊数据)的小提琴、真实表等,请在此处发布更新的 URL 以供审核,如果您无法。我已经用你调整的 SQL 发布了一个编辑,等待批准。 更新 fiddle 仅包含少量数据,例如:dbfiddle.uk/… 【参考方案1】:

如果您想要不同的案例计数(使用新表名进行调整):

SELECT cm_c.office_id
     , COUNT(DISTINCT cm_costs.case_number) AS case_count
     , SUM(total_charge)                    AS overall_cost
  FROM cm_categories   AS cm_c 
  JOIN cm_case_details AS cm_c_d ON cm_c.category_id   = cm_c_d.category_id 
  JOIN cm_costs                  ON cm_c_d.case_number = cm_costs.case_number
 GROUP BY cm_c.office_id
;

COUNT(DISTINCT x) 表示计算每个组的不同 x 值的数量。

还请注意,我们需要引用 case 表名。如前面的 cmets 所述,这是一个保留字。我建议避免使用保留字作为标识符(表、列等名称)。

我已从您的 SELECT 列表中删除了 case_number,因为它在功能上不依赖于 GROUP BY 条款。这意味着设计/查询不保证每个 office_id 最多有一个 case_number。

如果您想在选择列表中添加 case_number,则需要使用聚合形式(如 COUNT),如下所示:

SELECT cm_c.office_id
     , COUNT(DISTINCT cm_costs.case_number) AS case_count
     , SUM(total_charge)                    AS overall_cost
     , MIN(cost.case_number)                AS some_case_number
     , GROUP_CONCAT(cost.case_number)       AS all_cases
  FROM cm_categories   AS cm_c 
  JOIN cm_case_details AS cm_c_d ON cm_c.category_id   = cm_c_d.category_id 
  JOIN cm_costs                  ON cm_c_d.case_number = cm_costs.case_number
 GROUP BY cm_c.office_id
;

对于非常大的集合,请注意 GROUP_CONCAT,因为结果列的宽度可能会变得相当宽。

这是测试用例,进行了必要的调整:

Test case

有关GROUP BYfunctional dependence 的更多详细信息,请参阅以下链接:

group-by-handling

group-by-functional-dependence

【讨论】:

最好为这个答案添加一些解释。对你来说简单的事情对 OP/研究人员来说并不总是显而易见的 这个查询的问题在于,case 表中的记录数与此查询提供的记录数不同,因为它只考虑类别表中的那些行。例如:可能是类别表中只有一行 id 为 1 的类别,但在案例表中它有 5 行,并且此查询正在跳过该场景。 @ArunSharma 您在逻辑中使用了inner joins。如果您想要与某些表中没有匹配项的项目关联的结果,则需要outer join 行为。您能否提供一些与任何特殊情况和预期结果相关的测试数据?随意更改我提供的小提琴。

以上是关于从多对多关系中获取数据的主要内容,如果未能解决你的问题,请参考以下文章

使用非关联数据 (LINQ) 从多对多关系中获取值

如何在 Laravel 中从多对多关系的一对多关系中获取项目?

从多对多关系中获取结果

使用实体框架从多对多关系中选择数据

从多对多关系的桥接表中检索数据的查询[关闭]

核心数据 - 从多对多关系构建 NSPredicate