从 MySQL 中的两个视图中选择而不留下记录

Posted

技术标签:

【中文标题】从 MySQL 中的两个视图中选择而不留下记录【英文标题】:Select from two views in MySQL without leaving records 【发布时间】:2014-04-29 12:35:07 【问题描述】:

我需要从两个 mysql 视图中进行选择,它们是收入和费用视图,我需要它,这样如果我没有该记录的费用,它应该为 0,收入也是如此。

这是我目前的查询:

select e.v_name,e.v_number,sum(e.cost) Expenses, sum(i.income)Income from expenses_view e,
income_view i where i.v_number = e.v_number
group by v_number;

我只使用此查询获取两个视图中的记录,但我需要根据车辆编号从视图中选择既没有收入也没有费用的记录。

【问题讨论】:

不要使用隐式(逗号)连接语法。请参阅正确的 JOIN 语法。一切都会变得清晰。此外,必须有另一个表 - 存储所有资源的 PK,无论它们包含在任一表中。 【参考方案1】:

让我们首先阐明结果集的规范。我之所以要详细说明这一点,是因为我坚信良好的 SQL 会自然而然地源自清晰的规范。

    您希望每行 (v_name,v_number) 显示收入和支出的总和,零表示其中没有任何一个。 收入和支出来自不同的表。 您没有(至少您没有在问题中披露)包含 (v_name,v_number) 值的最终列表的单独表格。

因此,我们首先需要生成您的 v_number 的最终列表。这很容易

SELECT DISTINCT v_name, v_number FROM (
  SELECT v_name, v_number FROM expenses_view
   UNION 
  SELECT v_name, v_number FROM income_view
) AS u

现在看,这是一种非常可怕的方法。我们需要的是一个包含所有人员记录的表。但是不要紧。有时企业软件因为数据隐藏而需要这种东西。

接下来我们需要总结一下收入和支出。这将像这样工作:

SELECT v_number, SUM(cost) AS cost FROM expenses_view GROUP BY v_number

SELECT v_number, SUM(income) AS income FROM expenses_view GROUP BY v_number

您必须在加入这些表之前使用SUM() 进行聚合,因为 JOIN 操作会产生组合爆炸。如果您在 JOIN 之后执行 SUM() 操作,您的总和将太大;您将多次使用每个详细记录。

所以,这里我们有三个查询,每个查询生成一个虚拟表,每个 v_number 有一行。

    v_number -> v_name v_number -> 费用 v_number -> 收入

如果你很聪明,你会独立地对其中的每一个进行单元测试。

现在,我们使用 LEFT JOIN 将它们连接在一起,以获得您想要的结果集。我们需要 LEFT JOIN,因为普通的 JOIN 会忽略没有收入和支出记录的行。

SELECT v.v_name, v.v_number, 
       IFNULL(e.cost,0) AS cost,
       IFNULL(i.income,0) AS income
  FROM (
       /* first virtual table */
       ) AS v
  LEFT JOIN (
       /* second virtual table */
       ) AS e ON v.v_number = e.v_number
  LEFT JOIN (
       /* third virtual table */
       ) AS i ON v.v_number = i.v_number

看看情况如何?我们生成我们需要的清单(人员、成本、收入),然后将这些清单组合在一起以获得最终结果。

这是实际的查询。

SELECT v.v_name, v.v_number, 
       IFNULL(e.cost,0) AS cost,
       IFNULL(i.income,0) AS income
  FROM (
         /* first virtual table */
         SELECT DISTINCT v_name, v_number FROM (
            SELECT v_name, v_number FROM expenses_view
             UNION 
            SELECT v_name, v_number FROM income_view
          ) AS u
       ) AS v
  LEFT JOIN (
         /* second virtual table */
         SELECT v_number, SUM(cost) AS cost FROM expenses_view GROUP BY v_number
       ) AS e ON v.v_number = e.v_number
  LEFT JOIN (
         /* third virtual table */
         SELECT v_number, SUM(income) AS income FROM expenses_view GROUP BY v_number
       ) AS i ON v.v_number = i.v_number

这可能有点超出您的预期。但这是获得所需结果集的结构化且可预测的方式。

【讨论】:

以上是关于从 MySQL 中的两个视图中选择而不留下记录的主要内容,如果未能解决你的问题,请参考以下文章

Mysql 视图 - 连接中的选择数据返回超过 1 行

授予用户权限以仅查看 MySQL 视图而不查看其他内容

如果第一个没有可用记录,则从视图中选择并从一个表或另一个表中加入

MySQL 从具有重复引用条目的联合表中选择唯一记录

如何从mysql中的表中选择N条记录

如何在 MySQL 视图中生成序列号?