【问题标题】:SQL different joins not making any difference to resultSQL 不同的连接对结果没有任何影响
【发布时间】:2010-05-26 05:49:25
【问题描述】:

我正在尝试编写一个快速(哈哈!)的程序来组织我的一些财务信息。我理想中想要的是一个查询,它将从 TableA 返回所有包含财务信息的记录。每个月应该有一行,但在一个月没有交易的情况下,将没有记录。我得到这样的结果:


SELECT Period,Year,TotalValue FROM TableA WHERE Year='1997'

结果:

Period Year  TotalValue
1      1997  298.16
2      1997  435.25
4      1997  338.37
8      1997  336.07
9      1997  578.97
11     1997  361.23

通过加入一个表(在这个例子中是一个视图),它只包含一个字段Period,值从 1 到 12,我希望得到这样的结果:


SELECT p.Period,a.Year,a.TotalValue
FROM Periods AS p
LEFT JOIN TableA AS a ON p.Period = a.Period
WHERE Year='1997'

结果:

Period Year  TotalValue
1      1997  298.16
2      1997  435.25
3      NULL  NULL
4      1997  338.37
5      NULL  NULL
6      NULL  NULL
7      NULL  NULL
8      1997  336.07
9      1997  578.97
10     NULL  NULL
11     1997  361.23
12     NULL  NULL

无论我如何加入它,我实际上得到的是相同的结果(除了 CROSS JOIN 会发疯,但这真的不是我想要的,只是看看不同的加入是否在做任何事情) .即没有NULL记录,它只返回TableA中对应句点存在的记录,而不是不管从1到12的12条记录。 LEFT JOIN、RIGHT JOIN、INNER JOIN 都无法提供我期望的 NULL 记录。

我在 JOIN 中做错了什么明显的事情吗?我加入视图是否重要?


编辑 使用 Mark Byers 的示例,我尝试了以下操作:

SELECT p.Period,a.Year,a.TotalValue
FROM Periods AS p
LEFT JOIN TableA AS a ON (p.Period = a.Period) AND (a.Year = '1997')

结果:

Period Year  TotalValue
1      1997  298.16
2      1997  435.25
4      1997  338.37
8      1997  336.07
9      1997  578.97
11     1997  361.23

它以不同的方式有效地获得了相同的结果,但仍然没有获得 3、5、6、7 等的预期 NULL 条目。


非常感谢 Mark Byers 帮助制定了最终解决方案,记录在案的是:

SELECT p.Period, a.YEAR, SUM(a.Value) as TotalValue
FROM
    Periods as p
LEFT JOIN
    TableA as a
    ON d.Period = p.Period AND a.Year = '1997'
GROUP BY p.Period,a.Year,a.PERIOD
ORDER BY p.Period,a.Year;

实际上,还有一个 LedgerID 字段被分组,尽管最终结果保持不变:过滤需要在 JOIN 上进行,而不是在 JOIN 的结果上进行。

【问题讨论】:

  • 正如 FULL OUTER JOIN 答案留下的评论所暗示的那样,显然没有。想一想 - WHERE 子句过滤掉 JOIN 的结果有效地使 JOIN 的结果无效,因为那些连接的记录将包含 NULL 值。选择标准需要应用于实际的 JOIN。

标签: sql sql-server join


【解决方案1】:

这是错误的:

WHERE Year='1997'

您想要 Year 为 1997 或为 NULL 但由于 WHERE 子句而被过滤掉的行。改用这个:

LEFT JOIN TableA AS a
ON p.Period = a.Period
AND Year = '1997'

另请注意,您不需要保留 Periods 表。您还可以使用recursive CTE 动态生成它。您的递归 CTE 应如下所示:

WITH Periods (Period) AS
(
    SELECT 1
    UNION ALL
    SELECT Period + 1 FROM Periods WHERE Period < 12
)
SELECT * FROM Periods

【讨论】:

  • 这可能仍然有帮助,但仍然不能解决主要问题,抱歉。即使我完全去掉 WHERE 子句,我仍然会得到一份所有年份的列表,但没有任何预期的 NULL 记录。
  • Chrissi:“即使我完全取消了 WHERE 子句” 不——你不能那样做。这种类型的查询不适用于所有年份 - 仅适用于特定年份。如果你去掉了额外的子句,那么如果你在 any 年的每个月都有条目,那么你将不会得到 NULL。如果您想在 所有 年内获得 NULL,那么您需要一个完全不同的查询。那是你要的吗?如果是这样,您应该更新您的问题以明确这一点,因为从您的问题看来,您只对一年感兴趣,您可以使用此方法。
  • 不,只是一年。我已经更新了上述问题,以反映在尝试您的答案时会发生什么,谢谢。
  • @Chrissi:您确定您的递归 CTE 生成了正确的结果吗?试试SELECT * FROM Periods 看看会发生什么。
  • 当我添加了足够的 JOIN ON 子句时,您的原始答案毕竟有效。
【解决方案2】:

我想你需要的是LEFT OUTER JOIN

【讨论】:

  • LEFT JOINLEFT OUTER JOIN 完全相同。见stackoverflow.com/questions/406294/…
  • 抱歉,我使用的 JOIN 变体没有任何区别。
  • MikeJiang,想一想:你怎么会有左内连接或右内连接?如果您了解 INNER JOIN,您会意识到它没有任何意义。因此,您可以使用 LEFT JOIN 作为 LEFT OUTER JOIN 的简写
  • 嗨,这可能有效:从周期中选择 p.Period,a.Year,a.TotalValue 作为 p LEFT JOIN (SELSECT * from TableA WHERE Year='1997') 作为 ON p.Period = a.期间
【解决方案3】:

我想你正在寻找一个

FULL OUTER JOIN
因为对于每个 NULL “Year”,其对应的“TotalValue”也是 NULL!

【讨论】:

  • 这只是为与 WHERE 条件不匹配的所有内容生成 NULL。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-18
  • 2021-06-17
  • 1970-01-01
  • 2015-07-25
  • 2020-01-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多