【问题标题】:Retrieve all records from one table even if a related record can't be found in a related table即使在相关表中找不到相关记录,也从一个表中检索所有记录
【发布时间】:2013-09-13 22:55:17
【问题描述】:

我有一个检查记录的废物类型的应用程序。系统的一部分允许用户预测他们将回收多少废物,并在报告中列出预测的废物类型以及预测的废物数量和记录的实际废物。

它的工作方式是有一个名为forecastwaste 的表和一个名为wastestream 的表。 wastestream 保存所有关于实际已回收的废物类型的数据,forecastwaste 保存已预测的废物类型。 wastetypes 表包含用户可以选择的可用废物类型的名称。

我有这个 SQL 语句($contractid 包含合约的 id):

SELECT ws.wastetype, SUM(ws.recordedweight) totalWeight, SUM(ws.percent) totalPercent, wt.id, wt.category, wt.defrecycling, fw.tonnes 
FROM wastestream ws, wastetypes wt, forecastwaste fw 
WHERE ws.contractid = ".$contractid." 
AND fw.contractid = ".$contractid." 
AND ws.wastetype = wt.id 
AND fw.wastetype = wt.id 
GROUP BY ws.wastetype

但是,我遇到的问题是,如果 forecastewate 表中没有 wastestream 表中的废物类型,则查询将不会显示任何内容。我想得到它,以便如果在wastestream 表中找不到任何结果,查询仍将显示forecastewaste 记录并在找不到任何内容时返回0。当前查询不允许这样做。

我怎样才能使查询工作,以便它完成我需要的工作?

编辑
感谢 Bandydan,我重写了查询,现在看起来像这样:

SELECT ws.wastetype, SUM(ws.recordedweight) totalWeight, SUM(ws.percent) totalPercent, wt.id, wt.category, wt.defrecycling, fw.tonnes 
FROM c1skips.wastestream ws
LEFT JOIN c1skips.wastetypes wt ON (wt.id = ws.wastetype)
INNER JOIN c1skips.forecastwaste fw ON (wt.id = fw.wastetype)
WHERE fw.contractid = '602'
AND ws.contractid = '602'
GROUP BY ws.wastetype;

我也会解释一下我想要做得更好的事情。

我有一个名为 forecastwaste 的表,在该表中我有以下数据:

|---------------------------------|
| wastetype | tonnes | contractid |
|-----------|--------|------------|
|     1     |   10   |    602     |
|     2     |   20   |    602     |
|     3     |   50   |    602     |
|-----------|--------|------------|

然后使用该表查看wastestream 表,以了解回收了多少材料。 wastestream 表如下所示:

|-----------------------------------------|
| wastetype | recordedweight | contractid |
|-----------|----------------|------------|
|     1     |       2        |     602    |
|     1     |       4        |     602    |
|     2     |      20        |     602    |
|-----------|----------------|------------|

两个表都引用了wastetype 表,该表标识了带有废物类型的数字。

对于当前查询,它只会返回出现在wastestream 表中的结果。但是,我希望这样即使wastestream 表中没有记录,它也会返回 0。

编辑 2
我已将 COALESCE 添加到我的查询中,如下所示:

SELECT ws.wastetype, SUM(ws.recordedweight) totalWeight, SUM(ws.percent) totalPercent, wt.id, wt.category, wt.defrecycling, 
COALESCE(ws.recordedweight, 0) tonnes 
FROM c1skips.wastestream ws
LEFT JOIN c1skips.wastetypes wt ON (wt.id = ws.wastetype)
INNER JOIN c1skips.forecastwaste fw ON (wt.id = fw.wastetype)
WHERE fw.contractid = '602'
AND ws.contractid = '602'
GROUP BY ws.wastetype;

但结果还是一样。将是 SUM(ws.recordedweight) totalWeightSUM(ws.percent) totalPercent 返回 wastestream 表中的 NULL 值,但 forecaste 表中将有一个值试图引用它们,但 COALESCE 将不起作用用那个。

【问题讨论】:

  • 考虑首先将该语句转换为使用 INNER JOIN 的语句以简化可读性。然后就是使用 LEFT JOIN 的问题。

标签: mysql sql cakephp-2.0


【解决方案1】:

您需要在 forecastwaste 和 wastetypes 之间建立一个 Inner Join 以及一个到 wastestream 的 Left Join:

SELECT ws.wastetype, SUM(ws.recordedweight) totalWeight, SUM(ws.percent) totalPercent, wt.id, wt.category, wt.defrecycling, fw.tonnes 
FROM c1skips.forecastwaste fw
JOIN c1skips.wastetypes wt ON (wt.id = fw.wastetype)
LEFT JOIN c1skips.wastestream ws
ON (ws.contractid = fw.contractid) AND (ws.wastetype = fw.wastetype)
WHERE fw.contractid = '602'
GROUP BY ws.wastetype;

我将 fw.contractid = '602' 替换为 (ws.contractid = fw.contractid) 作为加入条件。现在不需要在两个地方写contractid,你可以在没有WHERE的情况下运行查询来返回所有行。

编辑:将外表从废物流更改为预测废物

【讨论】:

  • 此查询返回不正确的数据。如果我将ws.contractid 更改为fw.contractid,则会显示正确的数据。但是,0 值记录仍然没有显示出来。
  • 好的,你的外部表(即你想要所有行的表,即使没有匹配)是forecastwaste。我相应地更改了答案,希望现在是正确的。
【解决方案2】:

我认为您需要使用联接重写那个,然后您将能够使用 LEFT JOIN。它按您需要的方式工作。

几分钟后我能做的事情是这样的:

SELECT ws.wastetype, SUM(ws.recordedweight) totalWeight, SUM(ws.percent) totalPercent, wt.id, wt.category, wt.defrecycling, fw.tonnes 
    FROM wastetypes wt
    LEFT JOIN wastestream ws ON (wt.id = ws.wastetype)
    INNER JOIN forecastwaste fw USING(wt.id = fw.wastetype)
    WHERE wt.contractid = ".$contractid." 
    GROUP BY ws.wastetype

这里我假设你需要来自 wt 的信息,关于同一类型的信息,MAYBE 存在于 ws 中,以及关于该类型的信息来自 fw(肯定存在)。我不确定这是否正确,因为我没有要检查的表格,但我想向您展示整个想法。

看看that question的答案,你会找到解决问题的方法。

【讨论】:

    【解决方案3】:

    试试:

    SELECT
      wt.wastetype, wt.id, wt.category, wt.defrecycling,
      SUM(ws.recordedweight) totalWeight, SUM(ws.percent) totalPercent,
      COALESCE(fw.tonnes, 0) tonnes
    FROM c1skips.wastetypes wt
    LEFT JOIN c1skips.wastestream ws ON (wt.id = ws.wastetype)
    LEFT JOIN c1skips.forecastwaste fw ON (wt.id = fw.wastetype)
    WHERE fw.contractid = '602'
    AND ws.contractid = '602'
    GROUP BY ws.wastetype;
    

    注意FROM改成wastetypeswastestream移到LEFT JOIN还有一个函数COALESCE

    【讨论】:

    • 但是查询的其他部分呢?您仍然拥有FROM c1skips.wastestream,但应该使用LEFT JOIN 添加它。结果中的行不能在FROM 部分中定义的表中丢失。如果您运行我提出的整个查询,结果是什么?
    • wt.wastetype 不正确,因此我将其更改为 ws.wastetype,但查询显示的结果与我之前的查询相同。
    【解决方案4】:

    根据您的第二次编辑,我建议:

    SELECT ws.wastetype, SUM(COALESCE(ws.recordedweight, 0)) totalWeight, SUM(COALESCE(ws.percent, 0)) totalPercent, wt.id, wt.category, wt.defrecycling, 
    COALESCE(ws.recordedweight, 0) tonnes 
    FROM c1skips.forecastwaste fw
    LEFT JOIN c1skips.wastetypes wt ON (wt.id = fw.wastetype)
    LEFT JOIN c1skips.wastestream ws ON (wt.id = ws.wastetype)
    WHERE fw.contractid = '602'
    AND ws.contractid = '602'
    GROUP BY ws.wastetype;
    

    这应该可以通过在 sum 中使用 COALESCE 来防止空值,并将加入到forecastwaste 中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多